Commit add03b62 authored by Jack Jansen's avatar Jack Jansen

Handles were never disposed. Added an AutoDispose(onoff) method to control this.

Also added a Handle() function which is like Resource() but has auto-dispose on by default.
parent a17e0f1b
...@@ -47,6 +47,13 @@ extern PyObject *WinObj_WhichWindow(WindowPtr); ...@@ -47,6 +47,13 @@ extern PyObject *WinObj_WhichWindow(WindowPtr);
#define resNotFound -192 /* Can't include <Errors.h> because of Python's "errors.h" */ #define resNotFound -192 /* Can't include <Errors.h> because of Python's "errors.h" */
/* Function to dispose a resource, with a "normal" calling sequence */
static void
PyMac_AutoDisposeHandle(Handle h)
{
DisposeHandle(h);
}
static PyObject *Res_Error; static PyObject *Res_Error;
/* ---------------------- Object type Resource ---------------------- */ /* ---------------------- Object type Resource ---------------------- */
...@@ -58,6 +65,7 @@ PyTypeObject Resource_Type; ...@@ -58,6 +65,7 @@ PyTypeObject Resource_Type;
typedef struct ResourceObject { typedef struct ResourceObject {
PyObject_HEAD PyObject_HEAD
Handle ob_itself; Handle ob_itself;
void (*ob_freeit)(Handle ptr);
} ResourceObject; } ResourceObject;
PyObject *ResObj_New(itself) PyObject *ResObj_New(itself)
...@@ -68,6 +76,7 @@ PyObject *ResObj_New(itself) ...@@ -68,6 +76,7 @@ PyObject *ResObj_New(itself)
it = PyObject_NEW(ResourceObject, &Resource_Type); it = PyObject_NEW(ResourceObject, &Resource_Type);
if (it == NULL) return NULL; if (it == NULL) return NULL;
it->ob_itself = itself; it->ob_itself = itself;
it->ob_freeit = NULL;
return (PyObject *)it; return (PyObject *)it;
} }
ResObj_Convert(v, p_itself) ResObj_Convert(v, p_itself)
...@@ -97,7 +106,11 @@ ResObj_Convert(v, p_itself) ...@@ -97,7 +106,11 @@ ResObj_Convert(v, p_itself)
static void ResObj_dealloc(self) static void ResObj_dealloc(self)
ResourceObject *self; ResourceObject *self;
{ {
/* Cleanup of self->ob_itself goes here */ if (self->ob_freeit && self->ob_itself)
{
self->ob_freeit(self->ob_itself);
}
self->ob_itself = NULL;
PyMem_DEL(self); PyMem_DEL(self);
} }
...@@ -462,6 +475,25 @@ static PyObject *ResObj_LoadResource(_self, _args) ...@@ -462,6 +475,25 @@ static PyObject *ResObj_LoadResource(_self, _args)
return _res; return _res;
} }
static PyObject *ResObj_AutoDispose(_self, _args)
ResourceObject *_self;
PyObject *_args;
{
PyObject *_res = NULL;
int onoff, old = 0;
if (!PyArg_ParseTuple(_args, "i", &onoff))
return NULL;
if ( _self->ob_freeit )
old = 1;
if ( onoff )
_self->ob_freeit = PyMac_AutoDisposeHandle;
else
_self->ob_freeit = NULL;
return Py_BuildValue("i", old);
}
static PyMethodDef ResObj_methods[] = { static PyMethodDef ResObj_methods[] = {
{"HomeResFile", (PyCFunction)ResObj_HomeResFile, 1, {"HomeResFile", (PyCFunction)ResObj_HomeResFile, 1,
"() -> (short _rv)"}, "() -> (short _rv)"},
...@@ -503,6 +535,8 @@ static PyMethodDef ResObj_methods[] = { ...@@ -503,6 +535,8 @@ static PyMethodDef ResObj_methods[] = {
"Return this resource/handle as a Menu"}, "Return this resource/handle as a Menu"},
{"LoadResource", (PyCFunction)ResObj_LoadResource, 1, {"LoadResource", (PyCFunction)ResObj_LoadResource, 1,
"() -> None"}, "() -> None"},
{"AutoDispose", (PyCFunction)ResObj_AutoDispose, 1,
"(int)->int. Automatically DisposeHandle the object on Python object cleanup"},
{NULL, NULL, 0} {NULL, NULL, 0}
}; };
...@@ -1305,7 +1339,34 @@ static PyObject *Res_Resource(_self, _args) ...@@ -1305,7 +1339,34 @@ static PyObject *Res_Resource(_self, _args)
HLock(h); HLock(h);
memcpy(*h, buf, len); memcpy(*h, buf, len);
HUnlock(h); HUnlock(h);
return (PyObject *)ResObj_New(h); return ResObj_New(h);
}
static PyObject *Res_Handle(_self, _args)
PyObject *_self;
PyObject *_args;
{
PyObject *_res = NULL;
char *buf;
int len;
Handle h;
ResourceObject *rv;
if (!PyArg_ParseTuple(_args, "s#", &buf, &len))
return NULL;
h = NewHandle(len);
if ( h == NULL ) {
PyErr_NoMemory();
return NULL;
}
HLock(h);
memcpy(*h, buf, len);
HUnlock(h);
rv = (ResourceObject *)ResObj_New(h);
rv->ob_freeit = PyMac_AutoDisposeHandle;
return (PyObject *)rv;
} }
...@@ -1377,7 +1438,9 @@ static PyMethodDef Res_methods[] = { ...@@ -1377,7 +1438,9 @@ static PyMethodDef Res_methods[] = {
{"FSpCreateResFile", (PyCFunction)Res_FSpCreateResFile, 1, {"FSpCreateResFile", (PyCFunction)Res_FSpCreateResFile, 1,
"(FSSpec spec, OSType creator, OSType fileType, ScriptCode scriptTag) -> None"}, "(FSSpec spec, OSType creator, OSType fileType, ScriptCode scriptTag) -> None"},
{"Resource", (PyCFunction)Res_Resource, 1, {"Resource", (PyCFunction)Res_Resource, 1,
"Convert a string to a resource object.\n\nThe created resource object is actually just a handle.\nApply AddResource() to write it to a resource file.\n"}, "Convert a string to a resource object.\n\nThe created resource object is actually just a handle,\napply AddResource() to write it to a resource file.\nSee also the Handle() docstring.\n"},
{"Handle", (PyCFunction)Res_Handle, 1,
"Convert a string to a Handle object.\n\nResource() and Handle() are very similar, but objects created with Handle() are\nby default automatically DisposeHandle()d upon object cleanup. Use AutoDispose()\nto change this.\n"},
{NULL, NULL, 0} {NULL, NULL, 0}
}; };
...@@ -1422,7 +1485,6 @@ OptResObj_Convert(v, p_itself) ...@@ -1422,7 +1485,6 @@ OptResObj_Convert(v, p_itself)
} }
void initRes() void initRes()
{ {
PyObject *m; PyObject *m;
......
...@@ -13,14 +13,45 @@ if ( h == NULL ) { ...@@ -13,14 +13,45 @@ if ( h == NULL ) {
HLock(h); HLock(h);
memcpy(*h, buf, len); memcpy(*h, buf, len);
HUnlock(h); HUnlock(h);
return (PyObject *)ResObj_New(h); return ResObj_New(h);
""" """
f = ManualGenerator("Resource", resource_body) f = ManualGenerator("Resource", resource_body)
f.docstring = lambda: """Convert a string to a resource object. f.docstring = lambda: """Convert a string to a resource object.
The created resource object is actually just a handle. The created resource object is actually just a handle,
Apply AddResource() to write it to a resource file. apply AddResource() to write it to a resource file.
See also the Handle() docstring.
"""
functions.append(f)
handle_body = """
char *buf;
int len;
Handle h;
ResourceObject *rv;
if (!PyArg_ParseTuple(_args, "s#", &buf, &len))
return NULL;
h = NewHandle(len);
if ( h == NULL ) {
PyErr_NoMemory();
return NULL;
}
HLock(h);
memcpy(*h, buf, len);
HUnlock(h);
rv = (ResourceObject *)ResObj_New(h);
rv->ob_freeit = PyMac_AutoDisposeHandle;
return (PyObject *)rv;
"""
f = ManualGenerator("Handle", handle_body)
f.docstring = lambda: """Convert a string to a Handle object.
Resource() and Handle() are very similar, but objects created with Handle() are
by default automatically DisposeHandle()d upon object cleanup. Use AutoDispose()
to change this.
""" """
functions.append(f) functions.append(f)
...@@ -46,3 +77,22 @@ f = ResMethod(void, 'LoadResource', ...@@ -46,3 +77,22 @@ f = ResMethod(void, 'LoadResource',
(Handle, 'theResource', InMode), (Handle, 'theResource', InMode),
) )
resmethods.append(f) resmethods.append(f)
#
# A method to set the auto-dispose flag
#
AutoDispose_body = """
int onoff, old = 0;
if (!PyArg_ParseTuple(_args, "i", &onoff))
return NULL;
if ( _self->ob_freeit )
old = 1;
if ( onoff )
_self->ob_freeit = PyMac_AutoDisposeHandle;
else
_self->ob_freeit = NULL;
return Py_BuildValue("i", old);
"""
f = ManualGenerator("AutoDispose", AutoDispose_body)
f.docstring = lambda: "(int)->int. Automatically DisposeHandle the object on Python object cleanup"
resmethods.append(f)
...@@ -25,6 +25,13 @@ includestuff = includestuff + """ ...@@ -25,6 +25,13 @@ includestuff = includestuff + """
#include <string.h> #include <string.h>
#define resNotFound -192 /* Can't include <Errors.h> because of Python's "errors.h" */ #define resNotFound -192 /* Can't include <Errors.h> because of Python's "errors.h" */
/* Function to dispose a resource, with a "normal" calling sequence */
static void
PyMac_AutoDisposeHandle(Handle h)
{
DisposeHandle(h);
}
""" """
finalstuff = finalstuff + """ finalstuff = finalstuff + """
...@@ -65,7 +72,6 @@ OptResObj_Convert(v, p_itself) ...@@ -65,7 +72,6 @@ OptResObj_Convert(v, p_itself)
PyErr_SetString(PyExc_TypeError, "Resource required"); PyErr_SetString(PyExc_TypeError, "Resource required");
return 0; return 0;
} }
""" """
initstuff = initstuff + """ initstuff = initstuff + """
...@@ -120,7 +126,7 @@ ResObj_setattr(self, name, value) ...@@ -120,7 +126,7 @@ ResObj_setattr(self, name, value)
} }
""" """
class ResDefiniton(GlobalObjectDefinition): class ResDefinition(GlobalObjectDefinition):
def outputCheckNewArg(self): def outputCheckNewArg(self):
Output("if (itself == NULL) return PyMac_Error(resNotFound);") Output("if (itself == NULL) return PyMac_Error(resNotFound);")
...@@ -145,8 +151,23 @@ class ResDefiniton(GlobalObjectDefinition): ...@@ -145,8 +151,23 @@ class ResDefiniton(GlobalObjectDefinition):
def outputSetattr(self): def outputSetattr(self):
Output(setattrCode) Output(setattrCode)
def outputStructMembers(self):
GlobalObjectDefinition.outputStructMembers(self)
Output("void (*ob_freeit)(%s ptr);", self.itselftype)
def outputInitStructMembers(self):
GlobalObjectDefinition.outputInitStructMembers(self)
Output("it->ob_freeit = NULL;")
def outputCleanupStructMembers(self):
Output("if (self->ob_freeit && self->ob_itself)")
OutLbrace()
Output("self->ob_freeit(self->ob_itself);")
OutRbrace()
Output("self->ob_itself = NULL;")
resobject = ResDefiniton('Resource', 'ResObj', 'Handle') resobject = ResDefinition('Resource', 'ResObj', 'Handle')
module.addobject(resobject) module.addobject(resobject)
functions = [] functions = []
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment