lua-users home
lua-l archive

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


On Sat, Nov 16, 2013 at 9:04 AM, Geoff Smith <spammealot1@live.co.uk> wrote:
> If anyone can spare a bit of time to read the attached file and maybe fill
> in a few missing lines I would be most grateful.
> Is it possible to do without using  Cclosures or lightuserdata ? No idea,
> but would be good if they could be avoided for reasons of simplicity.   My
> attachment has been snipped down a bit to make it a smaller example file.

Geoff,

I took a look at your code.

I think that the answer is pretty simple and that you are down a path
that is over complicated.


First, you need a place to stash your C pointer, so that you can use
it as a reference to locate your userdata. The normal way to do this
is to make a table in the registry. Let's call it
"GRAPHICS_BUTTON_PTRS"

We need to make this a weak-keyed table, so that the reference doesn't
interfere with collection. We do this with a metatable `mt` that has:

```
mt.__mode = "v"
```
I'll assume that you know how to make a table in the registry and you
know how to assign a metatable to that table.


So, given that you've created this table, you're almost there.

In `udNewButton` you make the userdata `pToUserdata`.  That's your
user data, but the name you've given it suggests a disturbing
misunderstanding about the nature of userdata. We'll get to that
later.

Later on in that function, we get

```
   objPtr = createObject(LIB_GRAPHICS_BUTTON, (char*)objectName);  //
get a ptr to an unused button from the retired list and name this
button
```
I'm going to assume that this is the pointer returned by the event
that you are concerned with.

After this line, do something like this:

```
lua_getfield(L, LUA_REGISTRYINDEX, GRAPHICS_BUTTON_PTRS);
//there is now your weak table sitting on the stack.

lua_pushlightuserdata (L, objPtr);
//now your pointer is on the stack.
lua_pushvalue(L, 8);
//Assuming that the  userdata that you created earlier is at 8, this
will copy it to the top of the stack.

lua_settable(L, -3)
//This means:  In GRAPHICS_BUTTON_PTRS[objPtr] = pToUserdata

-------

So, much later, an event is fired, causing `buttonEventToLua(
OSLIB_OBJECT *pToObject)` to be called.

Rewrite this function:

```
///UNTESTED!!

void buttonEventToLua( OSLIB_OBJECT *pToObject)

{

    lua_State *local_L = L_Store;

    lua_getfield(L, LUA_REGISTRYINDEX, GRAPHICS_BUTTON_PTRS);
    lua_pushlightuserdata (L, pToObject);
    lua_gettable(L, -2);
    if(lua_isnil(L,-1))
        lua_error("Pointer not found!");

    ////your userdata is now at the top of the stack.

    ////do stuff.....

}

````

Does this make sense?


Here is something that's important to really understand:

Userdata is Lua's. You don't own it at all. Once you make it, assume
that Lua can destroy it at any time. This means that anything that
you've alloced in that object needs to be destroyed from that UD's
__gc metamethod and you can't be holding on to it anywhere else,
within lua. (or if you are, you need to manage it)

You can't "push" userdata on the stack and you can't store a pointer
to it, somewhere else. It's Lua's ONLY.

Once it is on the stack, you can move/copy/insert it from one position
to another. To get it on the stack, it needs to be there in a function
call from Lua OR you need to retrieve it from a known location.

Lightuserdata and the registry can be helpful here. Lightuserdata is a
void * and as such, it can only be equal to itself. This happens to
line up nicely with libraries that pass pointers in, which identify
the source of an event. We can use this pointer, which can only be
equal to itself, as the key value in a table that maps to a stashed
userdata value.

And then, BANG! You've got exactly what you need to respond to the event!

-Andrew