luaclass: take care of inheritance garbage collection

Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Julien Danjou 2009-10-02 15:48:32 +02:00
parent 92717a0849
commit f7746a198c
13 changed files with 67 additions and 71 deletions

View File

@ -163,11 +163,31 @@ luaA_class_add_property(lua_class_t *lua_class,
}); });
} }
/** Garbage collect a Lua object.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
*/
static int
luaA_class_gc(lua_State *L)
{
lua_object_t *item = lua_touserdata(L, 1);
signal_array_wipe(&item->signals);
/* Get the object class */
lua_class_t *class = luaA_class_get(L, 1);
/* Call the collector function of the class, and all its parent classes */
for(; class; class = class->parent)
if(class->collector)
class->collector(item);
return 0;
}
/** Setup a new Lua class. /** Setup a new Lua class.
* \param L The Lua VM state. * \param L The Lua VM state.
* \param name The class name. * \param name The class name.
* \param parent The parent class (inheritance). * \param parent The parent class (inheritance).
* \param allocator The allocator function used when creating a new object. * \param allocator The allocator function used when creating a new object.
* \param Collector The collector function used when garbage collecting an
* object.
* \param checker The check function to call when using luaA_checkudata(). * \param checker The check function to call when using luaA_checkudata().
* \param index_miss_property Function to call when an object of this class * \param index_miss_property Function to call when an object of this class
* receive a __index request on an unknown property. * receive a __index request on an unknown property.
@ -181,18 +201,19 @@ luaA_class_setup(lua_State *L, lua_class_t *class,
const char *name, const char *name,
lua_class_t *parent, lua_class_t *parent,
lua_class_allocator_t allocator, lua_class_allocator_t allocator,
lua_class_collector_t collector,
lua_class_checker_t checker, lua_class_checker_t checker,
lua_class_propfunc_t index_miss_property, lua_class_propfunc_t index_miss_property,
lua_class_propfunc_t newindex_miss_property, lua_class_propfunc_t newindex_miss_property,
const struct luaL_reg methods[], const struct luaL_reg methods[],
const struct luaL_reg meta[]) const struct luaL_reg meta[])
{ {
/* Create the metatable */ /* Create the object metatable */
lua_newtable(L); lua_newtable(L);
/* Register it with class pointer as key in the registry /* Register it with class pointer as key in the registry
* class-pointer -> metatable */ * class-pointer -> metatable */
lua_pushlightuserdata(L, class); lua_pushlightuserdata(L, class);
/* Duplicate the metatable */ /* Duplicate the object metatable */
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
lua_rawset(L, LUA_REGISTRYINDEX); lua_rawset(L, LUA_REGISTRYINDEX);
/* Now register class pointer with metatable as key in the registry /* Now register class pointer with metatable as key in the registry
@ -201,7 +222,12 @@ luaA_class_setup(lua_State *L, lua_class_t *class,
lua_pushlightuserdata(L, class); lua_pushlightuserdata(L, class);
lua_rawset(L, LUA_REGISTRYINDEX); lua_rawset(L, LUA_REGISTRYINDEX);
lua_pushvalue(L, -1); /* dup metatable 2 */ /* Duplicate objects metatable */
lua_pushvalue(L, -1);
/* Set garbage collector in the metatable */
lua_pushcfunction(L, luaA_class_gc);
lua_setfield(L, -2, "__gc");
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable 1 */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable 1 */
luaL_register(L, NULL, meta); /* 1 */ luaL_register(L, NULL, meta); /* 1 */
@ -210,6 +236,7 @@ luaA_class_setup(lua_State *L, lua_class_t *class,
lua_setmetatable(L, -2); /* set self as metatable 2 */ lua_setmetatable(L, -2); /* set self as metatable 2 */
lua_pop(L, 2); lua_pop(L, 2);
class->collector = collector;
class->allocator = allocator; class->allocator = allocator;
class->name = name; class->name = name;
class->index_miss_property = index_miss_property; class->index_miss_property = index_miss_property;

View File

@ -41,6 +41,7 @@ typedef struct
} lua_object_t; } lua_object_t;
typedef lua_object_t *(*lua_class_allocator_t)(lua_State *); typedef lua_object_t *(*lua_class_allocator_t)(lua_State *);
typedef void (*lua_class_collector_t)(lua_object_t *);
typedef int (*lua_class_propfunc_t)(lua_State *, lua_object_t *); typedef int (*lua_class_propfunc_t)(lua_State *, lua_object_t *);
@ -57,6 +58,8 @@ struct lua_class_t
lua_class_t *parent; lua_class_t *parent;
/** Allocator for creating new objects of that class */ /** Allocator for creating new objects of that class */
lua_class_allocator_t allocator; lua_class_allocator_t allocator;
/** Garbage collection function */
lua_class_collector_t collector;
/** Class properties */ /** Class properties */
lua_class_property_array_t properties; lua_class_property_array_t properties;
/** Function to call when a indexing an unknown property */ /** Function to call when a indexing an unknown property */
@ -76,7 +79,8 @@ void luaA_class_emit_signal(lua_State *, lua_class_t *, const char *, int);
void luaA_openlib(lua_State *, const char *, const struct luaL_reg[], const struct luaL_reg[]); void luaA_openlib(lua_State *, const char *, const struct luaL_reg[], const struct luaL_reg[]);
void luaA_class_setup(lua_State *, lua_class_t *, const char *, lua_class_t *, void luaA_class_setup(lua_State *, lua_class_t *, const char *, lua_class_t *,
lua_class_allocator_t, lua_class_checker_t, lua_class_allocator_t, lua_class_collector_t,
lua_class_checker_t,
lua_class_propfunc_t, lua_class_propfunc_t, lua_class_propfunc_t, lua_class_propfunc_t,
const struct luaL_reg[], const struct luaL_reg[]); const struct luaL_reg[], const struct luaL_reg[]);

View File

@ -300,16 +300,4 @@ luaA_object_tostring(lua_State *L)
return 1; return 1;
} }
/** Garbage collect a Lua object.
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
*/
int
luaA_object_gc(lua_State *L)
{
lua_object_t *item = lua_touserdata(L, 1);
signal_array_wipe(&item->signals);
return 0;
}
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80

View File

@ -191,7 +191,6 @@ int luaA_object_emit_signal_simple(lua_State *);
} }
int luaA_object_tostring(lua_State *); int luaA_object_tostring(lua_State *);
int luaA_object_gc(lua_State *);
#define LUA_OBJECT_META(prefix) \ #define LUA_OBJECT_META(prefix) \
{ "__tostring", luaA_object_tostring }, \ { "__tostring", luaA_object_tostring }, \

View File

@ -110,12 +110,11 @@ button_class_setup(lua_State *L)
{ {
LUA_OBJECT_META(button) LUA_OBJECT_META(button)
LUA_CLASS_META LUA_CLASS_META
{ "__gc", luaA_object_gc },
{ NULL, NULL } { NULL, NULL }
}; };
luaA_class_setup(L, &button_class, "button", NULL, luaA_class_setup(L, &button_class, "button", NULL,
(lua_class_allocator_t) button_new, NULL, (lua_class_allocator_t) button_new, NULL, NULL,
luaA_class_index_miss_property, luaA_class_newindex_miss_property, luaA_class_index_miss_property, luaA_class_newindex_miss_property,
button_methods, button_meta); button_methods, button_meta);
luaA_class_add_property(&button_class, A_TK_BUTTON, luaA_class_add_property(&button_class, A_TK_BUTTON,

View File

@ -38,10 +38,9 @@
* \param L The Lua VM state. * \param L The Lua VM state.
* \return The number of element pushed on stack. * \return The number of element pushed on stack.
*/ */
static int static void
luaA_client_gc(lua_State *L) client_wipe(client_t *c)
{ {
client_t *c = luaA_checkudata(L, 1, &client_class);
button_array_wipe(&c->buttons); button_array_wipe(&c->buttons);
key_array_wipe(&c->keys); key_array_wipe(&c->keys);
xcb_get_wm_protocols_reply_wipe(&c->protocols); xcb_get_wm_protocols_reply_wipe(&c->protocols);
@ -52,7 +51,6 @@ luaA_client_gc(lua_State *L)
p_delete(&c->alt_icon_name); p_delete(&c->alt_icon_name);
p_delete(&c->name); p_delete(&c->name);
p_delete(&c->alt_name); p_delete(&c->alt_name);
return luaA_object_gc(L);
} }
/** Change the clients urgency flag. /** Change the clients urgency flag.
@ -2031,12 +2029,12 @@ client_class_setup(lua_State *L)
{ "raise", luaA_client_raise }, { "raise", luaA_client_raise },
{ "lower", luaA_client_lower }, { "lower", luaA_client_lower },
{ "unmanage", luaA_client_unmanage }, { "unmanage", luaA_client_unmanage },
{ "__gc", luaA_client_gc },
{ NULL, NULL } { NULL, NULL }
}; };
luaA_class_setup(L, &client_class, "client", &window_class, luaA_class_setup(L, &client_class, "client", &window_class,
(lua_class_allocator_t) client_new, (lua_class_allocator_t) client_new,
(lua_class_collector_t) client_wipe,
(lua_class_checker_t) client_checker, (lua_class_checker_t) client_checker,
luaA_class_index_miss_property, luaA_class_newindex_miss_property, luaA_class_index_miss_property, luaA_class_newindex_miss_property,
client_methods, client_meta); client_methods, client_meta);

View File

@ -42,14 +42,12 @@ struct image
LUA_OBJECT_FUNCS(image_class, image_t, image) LUA_OBJECT_FUNCS(image_class, image_t, image)
static int static void
luaA_image_gc(lua_State *L) image_wipe(image_t *image)
{ {
image_t *p = luaA_checkudata(L, 1, &image_class); imlib_context_set_image(image->image);
imlib_context_set_image(p->image);
imlib_free_image(); imlib_free_image();
p_delete(&p->data); p_delete(&image->data);
return luaA_object_gc(L);
} }
static const char * static const char *
@ -816,12 +814,13 @@ image_class_setup(lua_State *L)
{ "draw_rectangle", luaA_image_draw_rectangle }, { "draw_rectangle", luaA_image_draw_rectangle },
{ "draw_rectangle_gradient", luaA_image_draw_rectangle_gradient }, { "draw_rectangle_gradient", luaA_image_draw_rectangle_gradient },
{ "draw_circle", luaA_image_draw_circle }, { "draw_circle", luaA_image_draw_circle },
{ "__gc", luaA_image_gc },
{ NULL, NULL } { NULL, NULL }
}; };
luaA_class_setup(L, &image_class, "image", NULL, luaA_class_setup(L, &image_class, "image", NULL,
(lua_class_allocator_t) image_new, NULL, (lua_class_allocator_t) image_new,
(lua_class_collector_t) image_wipe,
NULL,
luaA_class_index_miss_property, luaA_class_newindex_miss_property, luaA_class_index_miss_property, luaA_class_newindex_miss_property,
image_methods, image_meta); image_methods, image_meta);
luaA_class_add_property(&image_class, A_TK_WIDTH, luaA_class_add_property(&image_class, A_TK_WIDTH,

View File

@ -1122,12 +1122,11 @@ key_class_setup(lua_State *L)
{ {
LUA_OBJECT_META(key) LUA_OBJECT_META(key)
LUA_CLASS_META LUA_CLASS_META
{ "__gc", luaA_object_gc },
{ NULL, NULL }, { NULL, NULL },
}; };
luaA_class_setup(L, &key_class, "key", NULL, luaA_class_setup(L, &key_class, "key", NULL,
(lua_class_allocator_t) key_new, NULL, (lua_class_allocator_t) key_new, NULL, NULL,
luaA_class_index_miss_property, luaA_class_newindex_miss_property, luaA_class_index_miss_property, luaA_class_newindex_miss_property,
key_methods, key_meta); key_methods, key_meta);
luaA_class_add_property(&key_class, A_TK_KEY, luaA_class_add_property(&key_class, A_TK_KEY,

View File

@ -50,17 +50,11 @@ tag_unref_simplified(tag_t **tag)
luaA_object_unref(globalconf.L, *tag); luaA_object_unref(globalconf.L, *tag);
} }
/** Garbage collect a tag. static void
* \param L The Lua VM state. tag_wipe(tag_t *tag)
* \return 0.
*/
static int
luaA_tag_gc(lua_State *L)
{ {
tag_t *tag = luaA_checkudata(L, 1, &tag_class);
client_array_wipe(&tag->clients); client_array_wipe(&tag->clients);
p_delete(&tag->name); p_delete(&tag->name);
return luaA_object_gc(L);
} }
OBJECT_EXPORT_PROPERTY(tag, tag_t, selected) OBJECT_EXPORT_PROPERTY(tag, tag_t, selected)
@ -413,12 +407,13 @@ tag_class_setup(lua_State *L)
LUA_OBJECT_META(tag) LUA_OBJECT_META(tag)
LUA_CLASS_META LUA_CLASS_META
{ "clients", luaA_tag_clients }, { "clients", luaA_tag_clients },
{ "__gc", luaA_tag_gc },
{ NULL, NULL }, { NULL, NULL },
}; };
luaA_class_setup(L, &tag_class, "tag", NULL, luaA_class_setup(L, &tag_class, "tag", NULL,
(lua_class_allocator_t) tag_new, NULL, (lua_class_allocator_t) tag_new,
(lua_class_collector_t) tag_wipe,
NULL,
luaA_class_index_miss_property, luaA_class_newindex_miss_property, luaA_class_index_miss_property, luaA_class_newindex_miss_property,
tag_methods, tag_meta); tag_methods, tag_meta);
luaA_class_add_property(&tag_class, A_TK_NAME, luaA_class_add_property(&tag_class, A_TK_NAME,

View File

@ -118,12 +118,11 @@ timer_class_setup(lua_State *L)
LUA_CLASS_META LUA_CLASS_META
{ "start", luaA_timer_start }, { "start", luaA_timer_start },
{ "stop", luaA_timer_stop }, { "stop", luaA_timer_stop },
{ "__gc", luaA_object_gc },
{ NULL, NULL }, { NULL, NULL },
}; };
luaA_class_setup(L, &timer_class, "timer", NULL, luaA_class_setup(L, &timer_class, "timer", NULL,
(lua_class_allocator_t) timer_new, NULL, (lua_class_allocator_t) timer_new, NULL, NULL,
luaA_class_index_miss_property, luaA_class_newindex_miss_property, luaA_class_index_miss_property, luaA_class_newindex_miss_property,
timer_methods, timer_meta); timer_methods, timer_meta);
luaA_class_add_property(&timer_class, A_TK_TIMEOUT, luaA_class_add_property(&timer_class, A_TK_TIMEOUT,

View File

@ -37,7 +37,7 @@ LUA_OBJECT_FUNCS(wibox_class, wibox_t, wibox)
* \param w The wibox to wipe. * \param w The wibox to wipe.
*/ */
static void static void
wibox_wipe(wibox_t *w) wibox_wipe_resources(wibox_t *w)
{ {
if(w->window) if(w->window)
{ {
@ -61,19 +61,13 @@ wibox_wipe(wibox_t *w)
draw_context_wipe(&w->ctx); draw_context_wipe(&w->ctx);
} }
/** Take care of garbage collecting a wibox. static void
* \param L The Lua VM state. wibox_wipe(wibox_t *wibox)
* \return The number of elements pushed on stack, 0!
*/
static int
luaA_wibox_gc(lua_State *L)
{ {
wibox_t *wibox = luaA_checkudata(L, 1, &wibox_class);
p_delete(&wibox->cursor); p_delete(&wibox->cursor);
wibox_wipe(wibox); wibox_wipe_resources(wibox);
button_array_wipe(&wibox->buttons); button_array_wipe(&wibox->buttons);
widget_node_array_wipe(&wibox->widgets); widget_node_array_wipe(&wibox->widgets);
return luaA_object_gc(L);
} }
/** Wipe an array of widget_node. Release references to widgets. /** Wipe an array of widget_node. Release references to widgets.
@ -702,7 +696,7 @@ wibox_detach(lua_State *L, int udx)
wibox_clear_mouse_over(wibox); wibox_clear_mouse_over(wibox);
wibox_wipe(wibox); wibox_wipe_resources(wibox);
foreach(item, globalconf.wiboxes) foreach(item, globalconf.wiboxes)
if(*item == wibox) if(*item == wibox)
@ -1318,12 +1312,13 @@ wibox_class_setup(lua_State *L)
LUA_CLASS_META LUA_CLASS_META
{ "buttons", luaA_wibox_buttons }, { "buttons", luaA_wibox_buttons },
{ "geometry", luaA_wibox_geometry }, { "geometry", luaA_wibox_geometry },
{ "__gc", luaA_wibox_gc },
{ NULL, NULL }, { NULL, NULL },
}; };
luaA_class_setup(L, &wibox_class, "wibox", &window_class, luaA_class_setup(L, &wibox_class, "wibox", &window_class,
(lua_class_allocator_t) wibox_new, NULL, (lua_class_allocator_t) wibox_new,
(lua_class_collector_t) wibox_wipe,
NULL,
luaA_class_index_miss_property, luaA_class_newindex_miss_property, luaA_class_index_miss_property, luaA_class_newindex_miss_property,
wibox_methods, wibox_meta); wibox_methods, wibox_meta);
luaA_class_add_property(&wibox_class, A_TK_WIDGETS, luaA_class_add_property(&wibox_class, A_TK_WIDGETS,

View File

@ -35,18 +35,12 @@
LUA_OBJECT_FUNCS(widget_class, widget_t, widget); LUA_OBJECT_FUNCS(widget_class, widget_t, widget);
/** Collect a widget structure. static void
* \param L The Lua VM state. widget_wipe(widget_t *widget)
* \return 0
*/
static int
luaA_widget_gc(lua_State *L)
{ {
widget_t *widget = luaA_checkudata(L, 1, &widget_class);
if(widget->destructor) if(widget->destructor)
widget->destructor(widget); widget->destructor(widget);
button_array_wipe(&widget->buttons); button_array_wipe(&widget->buttons);
return luaA_object_gc(L);
} }
/** Get a widget node from a wibox by coords. /** Get a widget node from a wibox by coords.
@ -574,13 +568,13 @@ widget_class_setup(lua_State *L)
{ "extents", luaA_widget_extents }, { "extents", luaA_widget_extents },
{ "__index", luaA_widget_index }, { "__index", luaA_widget_index },
{ "__newindex", luaA_widget_newindex }, { "__newindex", luaA_widget_newindex },
{ "__gc", luaA_widget_gc },
{ NULL, NULL } { NULL, NULL }
}; };
luaA_class_setup(L, &widget_class, "widget", NULL, luaA_class_setup(L, &widget_class, "widget", NULL,
(lua_class_allocator_t) widget_new, NULL, (lua_class_allocator_t) widget_new,
NULL, NULL, (lua_class_collector_t) widget_wipe,
NULL, NULL, NULL,
widget_methods, widget_meta); widget_methods, widget_meta);
luaA_class_add_property(&widget_class, A_TK_VISIBLE, luaA_class_add_property(&widget_class, A_TK_VISIBLE,
(lua_class_propfunc_t) luaA_widget_set_visible, (lua_class_propfunc_t) luaA_widget_set_visible,

View File

@ -119,7 +119,7 @@ window_class_setup(lua_State *L)
}; };
luaA_class_setup(L, &window_class, "window", NULL, luaA_class_setup(L, &window_class, "window", NULL,
NULL, NULL, NULL, NULL, NULL,
luaA_class_index_miss_property, luaA_class_newindex_miss_property, luaA_class_index_miss_property, luaA_class_newindex_miss_property,
window_methods, window_meta); window_methods, window_meta);