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
|
%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)
|
||||||
|
|
|
@ -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