|
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 > |