Betawidget Lua interface:

* Alter the "(callback handler, callback destructor, void *userData)" typemap such that it can be used as a more generic member-function callback
  * Additionally place this typemap in a file of its own for greater ease of reuse
 * Use this new typemap (for type SWIGLUA_MEMBER_FN) in the interface definition because of its greater simplicity


git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@6438 4a71c877-e1ca-e34f-864e-861f7616d084
master
Giel van Schijndel 2008-12-06 20:00:20 +00:00
parent 3e9530696d
commit c71d586739
2 changed files with 72 additions and 94 deletions

View File

@ -1,4 +1,7 @@
%module betawidget %module betawidget
%include "lua_memberfnptr.i"
%{ %{
extern "C" { extern "C" {
#include "widget.h" #include "widget.h"
@ -13,47 +16,14 @@ extern "C" {
#include <vector> #include <vector>
typedef struct static bool callbackHandler(widget* const self, const event* const evt, int const handlerId, SWIGLUA_MEMBER_FN const * const callbackRef)
{
lua_State* L;
int table;
#ifndef NDEBUG
widget* self;
eventType type;
#endif
} lua_widget_callback;
static void createLuaCallbackTable(lua_State* const L)
{
// Create a table to hold the function and a weak table with additional data
lua_newtable(L); // callback = {}
lua_newtable(L); // weak = {}
// setmetatable(weak, { __mode = 'v' })
lua_newtable(L);
lua_pushstring(L, "v");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
// callback.weak = weak
lua_setfield(L, -2, "weak");
}
static bool callbackHandler(widget* const self, const event* const evt, int const handlerId, lua_widget_callback const * const callbackRef)
{ {
lua_State* const L = callbackRef->L; lua_State* const L = callbackRef->L;
const int stack_top = lua_gettop(L); const int stack_top = lua_gettop(L);
bool result; bool result;
assert(self == callbackRef->self);
assert(evt->type == callbackRef->type);
// callback.function(callback.weak.widget, evt, handlerId) // callback.function(callback.weak.widget, evt, handlerId)
lua_getref(L, callbackRef->table); swiglua_member_fn_get(callbackRef);
lua_getfield(L, -1, "function");
lua_getfield(L, -2, "weak");
lua_getfield(L, -1, "widget");
lua_replace(L, -2);
lua_remove(L, -3);
assert(self == (widget const *)((swig_lua_userdata*)lua_touserdata(L, -1))->ptr); assert(self == (widget const *)((swig_lua_userdata*)lua_touserdata(L, -1))->ptr);
@ -78,12 +48,10 @@ static bool callbackHandler(widget* const self, const event* const evt, int cons
return result; return result;
} }
static bool callbackDestructor(widget* const self, const event* const evt, int const handlerId, lua_widget_callback* const callbackRef) static bool callbackDestructor(widget* const self, const event* const evt, int const handlerId, SWIGLUA_MEMBER_FN* const callbackRef)
{ {
assert(self == callbackRef->self); swiglua_member_fn_clear(callbackRef);
lua_unref(callbackRef->L, callbackRef->table);
free(callbackRef);
return true; return true;
} }
%} %}
@ -227,57 +195,6 @@ struct animationFrame
$2 = &frameList[0]; $2 = &frameList[0];
} }
%typemap (in) (callback handler, callback destructor, void *userData)
{
lua_widget_callback* callbackRef;
static const int self_idx = 1;
_widget* self = 0;
if (!SWIG_isptrtype(L, self_idx))
SWIG_fail_arg("$symname", self_idx, "_widget *");
if (!lua_isfunction(L, $input))
SWIG_fail_arg("$symname", $input, "function");
if (!SWIG_IsOK(SWIG_ConvertPtr(L, self_idx, (void**)&self, SWIGTYPE_p__widget, 0)))
{
SWIG_fail_ptr("$symname", self_idx, SWIGTYPE_p__widget);
}
// Allocate a chunk of memory to place a reference to the function in
callbackRef = (lua_widget_callback*)malloc(sizeof(*callbackRef));
if (callbackRef == NULL)
{
lua_pushstring(L, "Error in $symname: Out of memory");
goto fail;
}
// Create a table to store the Lua callback info in
createLuaCallbackTable(L);
// callback.function = function
lua_pushvalue(L, $input);
lua_setfield(L, -2, "function");
// callback.weak.widget = self
lua_getfield(L, -1, "weak");
lua_pushvalue(L, self_idx);
lua_setfield(L, -2, "widget");
lua_pop(L, 1);
// Retrieve a reference to the callback table
callbackRef->L = L;
callbackRef->table = lua_ref(L, true);
$1 = (callback)callbackHandler;
$2 = (callback)callbackDestructor;
$3 = callbackRef;
#ifndef NDEBUG
callbackRef->self = self;
callbackRef->type = arg2;
#endif
}
%rename (widget) _widget; %rename (widget) _widget;
struct _widget struct _widget
{ {
@ -311,14 +228,14 @@ struct _widget
return widgetRemoveChild(WIDGET($self), child); return widgetRemoveChild(WIDGET($self), child);
} }
virtual int addEventHandler(eventType type, callback handler, callback destructor, void *userData) virtual int addEventHandler(eventType type, SWIGLUA_MEMBER_FN* handler)
{ {
return widgetAddEventHandler($self, type, handler, destructor, userData); return widgetAddEventHandler($self, type, (callback)callbackHandler, (callback)callbackDestructor, handler);
} }
virtual int addTimerEventHandler(eventType type, int interval, callback handler, callback destructor, void *userData) virtual int addTimerEventHandler(eventType type, int interval, SWIGLUA_MEMBER_FN* handler)
{ {
return widgetAddTimerEventHandler($self, type, interval, handler, destructor, userData); return widgetAddTimerEventHandler($self, type, interval, (callback)callbackHandler, (callback)callbackDestructor, handler);
} }
virtual void removeEventHandler(int id) virtual void removeEventHandler(int id)

View File

@ -0,0 +1,61 @@
%{
typedef struct
{
lua_State* L;
int table;
} SWIGLUA_MEMBER_FN;
static void swiglua_member_fn_get(SWIGLUA_MEMBER_FN const * const fn)
{
// memberfn.function(memberfn.weak.self, ...
lua_getref(fn->L, fn->table);
lua_getfield(fn->L, -1, "function");
lua_getfield(fn->L, -2, "weak");
lua_getfield(fn->L, -1, "self");
lua_replace(fn->L, -2);
lua_remove(fn->L, -3);
}
static void swiglua_member_fn_clear(SWIGLUA_MEMBER_FN* const fn)
{
lua_unref(fn->L, fn->table);
free(fn);
}
%}
%typemap (in, checkfn="lua_isfunction") SWIGLUA_MEMBER_FN*
%{
// Allocate a chunk of memory to place a reference to the function in
$1 = (SWIGLUA_MEMBER_FN*)malloc(sizeof(*$1));
if ($1 == NULL)
{
lua_pushstring(L, "Error in $symname: Out of memory");
goto fail;
}
/* Create a table to hold the function and a weak table with the self object in it */
// callback = { function = function }
lua_newtable(L); // callback = { function = function }
lua_pushvalue(L, $input);
lua_setfield(L, -2, "function");
// weak = {}
lua_newtable(L);
// setmetatable(weak, { __mode = 'v' })
lua_newtable(L);
lua_pushstring(L, "v");
lua_setfield(L, -2, "__mode");
lua_setmetatable(L, -2);
// weak.widget = self
lua_pushvalue(L, 1);
lua_setfield(L, -2, "self");
// callback.weak = weak
lua_setfield(L, -2, "weak");
// Retrieve a reference to the callback table
$1->L = L;
$1->table = lua_ref(L, true);
%}