lua-users home
lua-l archive

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


It was thus said that the Great Geoff Smith once stated:
> I am really hoping someone could help me with this question please as I am
> totally stuck on it for now.
>  
> I am trying to implement a userdata via the C API,  to give me this type
> of functionality
>  
> btn1 = graphics.newButton(x,y,width,ht, "pressMe")
> btn1:setText("Different Text")
> btn1:setFont("Arial")
>  
> That's OK I think I have got that figured out and largely working, but the
> next thing I want to do is call a user defined Lua action function on the
> button instance. For example
>  
> In Lua
>  
> function btn1:action(someArbitrayParamBackFromC)
>      print("ouch someone just poked btn1")
> end
>  
> How can I call that Lua button instance function from C when I have
> detected the key is pressed ?

  The method I use [1] runs along these lines:

	static int Xdisplay_window(lua_State *L)
	{
	  Window *window;
	  
	  /* ... a bunch of code ... */
	  
	  window  = lua_newuserdata(L,sizeof(Window));
	  *window = XCreateWindow(...);

	  /* use this table for __index and __newindex */

	  lua_createtable(L,0,0);
	  lua_pushvalue(L,-1);
	  lua_setfield(L,-1,"__index");
	  lua_pushvalue(L,-1);
	  lua_setfield(L,-2,"__newindex");

	  /* populate predefined functions into this table */

	  luaL_register(L,NULL,Xwindow_metatable);

	   /* set as the metatable for our userdata */

	  lua_setmetatable(L,-2);
	}
	
  By giving each created window its own distinct metatable, I can attach
arbitrary Lua values to the "window". So, for instance, in Lua, I can do:

	  window = display:window(...)
	  window.somedata = 3
	  window.callback = function() ... end
	  
  So then, I could do the following:
  
  	function window:action()
  	  print("Hey! Somebody hit me!")
  	end
  	
  And in C code, when I detected that the window has been acted upon:
  
  	/*-----------------------------------------------------------------
  	; can't use luaL_checkudata() since we have a custom metatable.  I
  	; have a work around for it, but I'm skipping that code as it would
  	; otherwise clutter the example.
	;-------------------------------------------------------------------*/
  	 
  	Window *window = ... /* code to get object */;
  	if (luaL_getmetafield(L,-1,"action") == 0)
  	  return; /* no action defined, just ignore for now */
  	lua_pushvalue(L,-2);	/* push window parameter into place */
  	lua_call(L,1,0);	/* call function with window as a parameter */

(or use lua_pcall()---depends on how you want to handle potential errors)

  Yes, this does mean you can't have a single instance of a metatable for
all the objects, but for me, the ability to treat the userdata as a Lua
table outweighs the downsides.  

  -spc

[1]	A (private so far) project to create X11 bindings [2] to Lua.  It's
	more of a instructional thing for me and isn't really meant for
	public consumption.  At the very least, you would need to understand
	Xlib to even use it.

[2]	Xlib level.  About as low as you can go without touching the actual
	X protocol.