lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


2007/8/18, Merick <Merick_TeVaran@comcast.net>:
> Jérôme Vuarand wrote:
> > Can you send the prototype of the C function you are calling to
> > register a callback, along with the prototype of that callback ?
>
> function ui_cf Cdecl(Byval L As lua_State Ptr) As Integer
>     if lua_gettop(L) <> 8 then return lual_error(L, "[UI.CreateFrame]
> takes 8 args")
>     dim ownerbox  as UI_BOX_PTR = 0
>     dim As integer _
>         id     = lual_checknumber(L, 2),  _
>           x         = lual_checknumber(L, 3),  _
>           y        = lual_checknumber(L, 4),  _
>           w         = lual_checknumber(L, 5),  _
>           h       = lual_checknumber(L, 6),  _
>           flags = lual_checknumber(L, 8)
>      dim as string func_string = *lual_checkstring(L,7)
>     var ret = UI_CreateFrame(ownerbox, id, x, y, w, h,
> @callback_function , flags)
> end function
>
> ----
> In this line of the ui_cf  function:     var ret =
> UI_CreateFrame(ownerbox, id, x, y, w, h, @callback_function , flags)
> the argument  '@callback_function' is the function that I need to create
> that will link to a lua function, but I don't really know where to begin
>
> You can get the library I'm using from this page:
>
> http://www.execulink.com/~coder/freebasic/jmgui.html

It's a Freebasic specific question. It depends if the language handle
closures or not. In C, which do not handle closures, when registering
a callback you usually pass a function pointer and a data pointer. For
example :

typedef void (*callback_t)(void* data);
int register_callback(void* data, callback_t func);

With that kind of API, you have to create a structure to hold the Lua
state pointer and the reference to your Lua closure :

struct callback_t {
    lua_State* L;
    int index;
};

Your callback will typically take a void* parameter :

void callback(void* data)
{
    struct callback_t* cb = data;
    lua_State* L = cb->L;
    lua_rawgeti(L, LUA_REGISTRYINDEX, cb->index);
    lua_call(L, 1, 0);
}

Then in your lua_CFunction you allocate the structure and pass it to
the callback registration function :

int lua__register_callback(lua_State* L)
    luaL_checktype(L, 1, LUA_TFUNCTION);

    struct callback_t* cb = malloc(sizeof(struct callback_t));
    cb->L = L;
    lua_pushvalue(L, 1);
    cb->index = luaL_ref(L, LUA_REGISTRYINDEX);

    register_callback(cb, callback);
}

At some point you will have to free the structure, but that depend on
how callbacks are deregistered.

If the callback registration function doesn't take a data pointer, you
have to store it in a global variable. That's not very clean and will
lead to problem if you have several callbacks at the same time.