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-861f7616d084master
parent
3e9530696d
commit
c71d586739
|
@ -1,4 +1,7 @@
|
|||
%module betawidget
|
||||
|
||||
%include "lua_memberfnptr.i"
|
||||
|
||||
%{
|
||||
extern "C" {
|
||||
#include "widget.h"
|
||||
|
@ -13,47 +16,14 @@ extern "C" {
|
|||
|
||||
#include <vector>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
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)
|
||||
static bool callbackHandler(widget* const self, const event* const evt, int const handlerId, SWIGLUA_MEMBER_FN const * const callbackRef)
|
||||
{
|
||||
lua_State* const L = callbackRef->L;
|
||||
const int stack_top = lua_gettop(L);
|
||||
bool result;
|
||||
|
||||
assert(self == callbackRef->self);
|
||||
assert(evt->type == callbackRef->type);
|
||||
|
||||
// callback.function(callback.weak.widget, evt, handlerId)
|
||||
lua_getref(L, callbackRef->table);
|
||||
lua_getfield(L, -1, "function");
|
||||
lua_getfield(L, -2, "weak");
|
||||
lua_getfield(L, -1, "widget");
|
||||
lua_replace(L, -2);
|
||||
lua_remove(L, -3);
|
||||
swiglua_member_fn_get(callbackRef);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
%}
|
||||
|
@ -227,57 +195,6 @@ struct animationFrame
|
|||
$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;
|
||||
struct _widget
|
||||
{
|
||||
|
@ -311,14 +228,14 @@ struct _widget
|
|||
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)
|
||||
|
|
|
@ -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);
|
||||
%}
|
Loading…
Reference in New Issue