From f7746a198cfb6a49d171a8d1d1a6d634220342a8 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Fri, 2 Oct 2009 15:48:32 +0200 Subject: [PATCH] luaclass: take care of inheritance garbage collection Signed-off-by: Julien Danjou --- common/luaclass.c | 33 ++++++++++++++++++++++++++++++--- common/luaclass.h | 6 +++++- common/luaobject.c | 12 ------------ common/luaobject.h | 1 - objects/button.c | 3 +-- objects/client.c | 8 +++----- objects/image.c | 15 +++++++-------- objects/key.c | 3 +-- objects/tag.c | 15 +++++---------- objects/timer.c | 3 +-- objects/wibox.c | 21 ++++++++------------- objects/widget.c | 16 +++++----------- objects/window.c | 2 +- 13 files changed, 67 insertions(+), 71 deletions(-) diff --git a/common/luaclass.c b/common/luaclass.c index 97c8a41fe..5b3bdc224 100644 --- a/common/luaclass.c +++ b/common/luaclass.c @@ -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. * \param L The Lua VM state. * \param name The class name. * \param parent The parent class (inheritance). * \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 index_miss_property Function to call when an object of this class * 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, lua_class_t *parent, lua_class_allocator_t allocator, + lua_class_collector_t collector, lua_class_checker_t checker, lua_class_propfunc_t index_miss_property, lua_class_propfunc_t newindex_miss_property, const struct luaL_reg methods[], const struct luaL_reg meta[]) { - /* Create the metatable */ + /* Create the object metatable */ lua_newtable(L); /* Register it with class pointer as key in the registry * class-pointer -> metatable */ lua_pushlightuserdata(L, class); - /* Duplicate the metatable */ + /* Duplicate the object metatable */ lua_pushvalue(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); /* 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_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 */ 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_pop(L, 2); + class->collector = collector; class->allocator = allocator; class->name = name; class->index_miss_property = index_miss_property; diff --git a/common/luaclass.h b/common/luaclass.h index 425fd7a33..dbcedba59 100644 --- a/common/luaclass.h +++ b/common/luaclass.h @@ -41,6 +41,7 @@ typedef struct } lua_object_t; 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 *); @@ -57,6 +58,8 @@ struct lua_class_t lua_class_t *parent; /** Allocator for creating new objects of that class */ lua_class_allocator_t allocator; + /** Garbage collection function */ + lua_class_collector_t collector; /** Class properties */ lua_class_property_array_t properties; /** 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_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, const struct luaL_reg[], const struct luaL_reg[]); diff --git a/common/luaobject.c b/common/luaobject.c index 10ceb7a80..0af0ad178 100644 --- a/common/luaobject.c +++ b/common/luaobject.c @@ -300,16 +300,4 @@ luaA_object_tostring(lua_State *L) 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 diff --git a/common/luaobject.h b/common/luaobject.h index 056368bd2..dab3918ed 100644 --- a/common/luaobject.h +++ b/common/luaobject.h @@ -191,7 +191,6 @@ int luaA_object_emit_signal_simple(lua_State *); } int luaA_object_tostring(lua_State *); -int luaA_object_gc(lua_State *); #define LUA_OBJECT_META(prefix) \ { "__tostring", luaA_object_tostring }, \ diff --git a/objects/button.c b/objects/button.c index 679ec47e0..db6383904 100644 --- a/objects/button.c +++ b/objects/button.c @@ -110,12 +110,11 @@ button_class_setup(lua_State *L) { LUA_OBJECT_META(button) LUA_CLASS_META - { "__gc", luaA_object_gc }, { NULL, 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, button_methods, button_meta); luaA_class_add_property(&button_class, A_TK_BUTTON, diff --git a/objects/client.c b/objects/client.c index a37b489ff..a348afc07 100644 --- a/objects/client.c +++ b/objects/client.c @@ -38,10 +38,9 @@ * \param L The Lua VM state. * \return The number of element pushed on stack. */ -static int -luaA_client_gc(lua_State *L) +static void +client_wipe(client_t *c) { - client_t *c = luaA_checkudata(L, 1, &client_class); button_array_wipe(&c->buttons); key_array_wipe(&c->keys); 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->name); p_delete(&c->alt_name); - return luaA_object_gc(L); } /** Change the clients urgency flag. @@ -2031,12 +2029,12 @@ client_class_setup(lua_State *L) { "raise", luaA_client_raise }, { "lower", luaA_client_lower }, { "unmanage", luaA_client_unmanage }, - { "__gc", luaA_client_gc }, { NULL, NULL } }; luaA_class_setup(L, &client_class, "client", &window_class, (lua_class_allocator_t) client_new, + (lua_class_collector_t) client_wipe, (lua_class_checker_t) client_checker, luaA_class_index_miss_property, luaA_class_newindex_miss_property, client_methods, client_meta); diff --git a/objects/image.c b/objects/image.c index 48e8cf5a9..689c38eaf 100644 --- a/objects/image.c +++ b/objects/image.c @@ -42,14 +42,12 @@ struct image LUA_OBJECT_FUNCS(image_class, image_t, image) -static int -luaA_image_gc(lua_State *L) +static void +image_wipe(image_t *image) { - image_t *p = luaA_checkudata(L, 1, &image_class); - imlib_context_set_image(p->image); + imlib_context_set_image(image->image); imlib_free_image(); - p_delete(&p->data); - return luaA_object_gc(L); + p_delete(&image->data); } static const char * @@ -816,12 +814,13 @@ image_class_setup(lua_State *L) { "draw_rectangle", luaA_image_draw_rectangle }, { "draw_rectangle_gradient", luaA_image_draw_rectangle_gradient }, { "draw_circle", luaA_image_draw_circle }, - { "__gc", luaA_image_gc }, { NULL, 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, image_methods, image_meta); luaA_class_add_property(&image_class, A_TK_WIDTH, diff --git a/objects/key.c b/objects/key.c index 578a2c717..3c8fe94b2 100644 --- a/objects/key.c +++ b/objects/key.c @@ -1122,12 +1122,11 @@ key_class_setup(lua_State *L) { LUA_OBJECT_META(key) LUA_CLASS_META - { "__gc", luaA_object_gc }, { NULL, 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, key_methods, key_meta); luaA_class_add_property(&key_class, A_TK_KEY, diff --git a/objects/tag.c b/objects/tag.c index 4672d118f..f260f2704 100644 --- a/objects/tag.c +++ b/objects/tag.c @@ -50,17 +50,11 @@ tag_unref_simplified(tag_t **tag) luaA_object_unref(globalconf.L, *tag); } -/** Garbage collect a tag. - * \param L The Lua VM state. - * \return 0. - */ -static int -luaA_tag_gc(lua_State *L) +static void +tag_wipe(tag_t *tag) { - tag_t *tag = luaA_checkudata(L, 1, &tag_class); client_array_wipe(&tag->clients); p_delete(&tag->name); - return luaA_object_gc(L); } OBJECT_EXPORT_PROPERTY(tag, tag_t, selected) @@ -413,12 +407,13 @@ tag_class_setup(lua_State *L) LUA_OBJECT_META(tag) LUA_CLASS_META { "clients", luaA_tag_clients }, - { "__gc", luaA_tag_gc }, { NULL, 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, tag_methods, tag_meta); luaA_class_add_property(&tag_class, A_TK_NAME, diff --git a/objects/timer.c b/objects/timer.c index c4708e2f2..947b20255 100644 --- a/objects/timer.c +++ b/objects/timer.c @@ -118,12 +118,11 @@ timer_class_setup(lua_State *L) LUA_CLASS_META { "start", luaA_timer_start }, { "stop", luaA_timer_stop }, - { "__gc", luaA_object_gc }, { NULL, 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, timer_methods, timer_meta); luaA_class_add_property(&timer_class, A_TK_TIMEOUT, diff --git a/objects/wibox.c b/objects/wibox.c index 05c90960d..14c10c64e 100644 --- a/objects/wibox.c +++ b/objects/wibox.c @@ -37,7 +37,7 @@ LUA_OBJECT_FUNCS(wibox_class, wibox_t, wibox) * \param w The wibox to wipe. */ static void -wibox_wipe(wibox_t *w) +wibox_wipe_resources(wibox_t *w) { if(w->window) { @@ -61,19 +61,13 @@ wibox_wipe(wibox_t *w) draw_context_wipe(&w->ctx); } -/** Take care of garbage collecting a wibox. - * \param L The Lua VM state. - * \return The number of elements pushed on stack, 0! - */ -static int -luaA_wibox_gc(lua_State *L) +static void +wibox_wipe(wibox_t *wibox) { - wibox_t *wibox = luaA_checkudata(L, 1, &wibox_class); p_delete(&wibox->cursor); - wibox_wipe(wibox); + wibox_wipe_resources(wibox); button_array_wipe(&wibox->buttons); widget_node_array_wipe(&wibox->widgets); - return luaA_object_gc(L); } /** 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_wipe(wibox); + wibox_wipe_resources(wibox); foreach(item, globalconf.wiboxes) if(*item == wibox) @@ -1318,12 +1312,13 @@ wibox_class_setup(lua_State *L) LUA_CLASS_META { "buttons", luaA_wibox_buttons }, { "geometry", luaA_wibox_geometry }, - { "__gc", luaA_wibox_gc }, { NULL, NULL }, }; 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, wibox_methods, wibox_meta); luaA_class_add_property(&wibox_class, A_TK_WIDGETS, diff --git a/objects/widget.c b/objects/widget.c index 955325a49..a0f0a3bd1 100644 --- a/objects/widget.c +++ b/objects/widget.c @@ -35,18 +35,12 @@ LUA_OBJECT_FUNCS(widget_class, widget_t, widget); -/** Collect a widget structure. - * \param L The Lua VM state. - * \return 0 - */ -static int -luaA_widget_gc(lua_State *L) +static void +widget_wipe(widget_t *widget) { - widget_t *widget = luaA_checkudata(L, 1, &widget_class); if(widget->destructor) widget->destructor(widget); button_array_wipe(&widget->buttons); - return luaA_object_gc(L); } /** Get a widget node from a wibox by coords. @@ -574,13 +568,13 @@ widget_class_setup(lua_State *L) { "extents", luaA_widget_extents }, { "__index", luaA_widget_index }, { "__newindex", luaA_widget_newindex }, - { "__gc", luaA_widget_gc }, { NULL, NULL } }; luaA_class_setup(L, &widget_class, "widget", NULL, - (lua_class_allocator_t) widget_new, NULL, - NULL, NULL, + (lua_class_allocator_t) widget_new, + (lua_class_collector_t) widget_wipe, + NULL, NULL, NULL, widget_methods, widget_meta); luaA_class_add_property(&widget_class, A_TK_VISIBLE, (lua_class_propfunc_t) luaA_widget_set_visible, diff --git a/objects/window.c b/objects/window.c index cb33e7918..9fb979c6d 100644 --- a/objects/window.c +++ b/objects/window.c @@ -119,7 +119,7 @@ window_class_setup(lua_State *L) }; luaA_class_setup(L, &window_class, "window", NULL, - NULL, NULL, + NULL, NULL, NULL, luaA_class_index_miss_property, luaA_class_newindex_miss_property, window_methods, window_meta);