lua-users home
lua-l archive

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


Hello Andrew
 
Thanks again for trying to assist,  I think we just proved its tricky to formulate a clear question on a mailing list and to understand a partially complete piece of code out of context.
 
Let me try to clarify the question again
 
I want to be able to call a fixed name Lua function on my btn userdata instance.
 
btn1 = newButton(x,y, etc)
 
function btn1:action()
      print("this button was pressed")
end

The code I posted I have tested and works for assorted C functions and the garbage collection, __tostring etc.
 
But for the Lua side btn:action() function  I cant get a reference to it to call it via a pcall. That's the one thing that I am stuck on
 
Your solution below didn't even mention an "action" string, so it ignored the bit I am stuck on.
 
Also I didn't explain clearly but   pToObject  is a ptr to the button object in my C side graphics library, Lua doesn't need to know about that so pushing it on the stack cant be correct.
 
 `pToUserdata`.  is the ptr to the btn1 userdata in my example
>  but the name you've given it suggests a disturbing misunderstanding
 
its a ptr to a userdata block for that specific instance, so I didn't see why you thought it implied a misunderstanding ?
 
 
I could probably workaround this problem by forcing the user to do something like
 
btn1:registerHandler(myHandlerFunc)
 
I think I know how to code this alternate technique, but having a fixed btn1:action function seemed a better idea and saves the user having to register a function when the button is created.
 
And anyway this is bugging the heck out of me now and I want to solve it ! :)  If I ever figure it out I will write a web page up on it. The technique to call a fixed name Lua defined function on a userdata instance is currently sadly lacking in all of the Lua literature out there.
 
Regards Geoff
 
 
 
 
 
 
 
 
 
> From: andrew.starks@trms.com
> Date: Sat, 16 Nov 2013 14:29:19 -0600
> To: lua-l@lists.lua.org
> Subject: Re: Another userdata question
>
> 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
>