Creating Lua globals in Objective C/C from userdata - objective-c

I am working on a library to allow Lua (5.2) scripting of games in iOS 5.x. I have created a class and added bindings to allow it to be created and accessed form Lua. The C initializer method called from Lua is given below:
static int newGeminiObject(lua_State *L){
GeminiObject *go = [[GeminiObject alloc] initWithLuaState:L];
GeminiObject **lgo = (GeminiObject **)lua_newuserdata(L, sizeof(GeminiObject *));
*lgo = go;
luaL_getmetatable(L, GEMINI_OBJECT_LUA_KEY);
lua_setmetatable(L, -2);
lua_newtable(L);
lua_setuservalue(L, -2);
NSLog(#"New GeminiObject created");
// add this new object to the globall list of objects
[[Gemini shared].geminiObjects addObject:go];
return 1;
}
This assigns a metatable which is set up elsewhere to provide access to various methods. Additionally, it attaches a table as a uservalue to allow script code to assign attributes to the objects.
I can create these objects in Lua scripts with no problem:
require "gemini"
x = gemini.new()
x:addEventListener("touch", objectTouched)
Here objectTouched is a a Lua method defined elsewhere that handles a touch event. Here addEventListener binds it to touch events.
These objects work just fine. When I attempt to create one from C, however, I am running into problems. I can create the object, but trying to assign it to a global and then invoke it in a script fails.
The following C code runs
-(void) addRuntimeObject {
GeminiObject *rt = [[GeminiObject alloc] initWithLuaState:L];
GeminiObject **lruntime = (GeminiObject **)lua_newuserdata(L, sizeof(GeminiObject *));
*lruntime = rt;
// set the metatable - effectively declaring the type for this object
luaL_getmetatable(L, GEMINI_OBJECT_LUA_KEY);
lua_setmetatable(L, -2);
// add a table to hold anything the user wants to add
lua_newtable(L);
lua_setuservalue(L, -2);
// create an entry in the global table
lua_setglobal(L, "Runtime");
// empty the stack
lua_pop(L, lua_gettop(L));
}
This should define a global named "Runtime". Trying to access this variable from a script like this
Runtime:addEventListener("enterFrame", enterFrame)
Results in the following error:
attempt to index global 'Runtime' (a userdata value)
It is a userdata value, but this doesn't seem to matter when I create one in Lua directly. The metatable binding provides access to the methods and metamethods. Again, this works fine if the object is created from Lua, just not when it is created in C.
Any ideas as to what I'm doing wrong here, or what the correct way to make a global from userdata is?
EDIT
Based on comments below regarding confusion about GEMINI_OBJECT_LUA_KEY, I thought I would list the code that is actually used in the binding:
static const struct luaL_Reg geminiObjectLib_f [] = {
{"new", newGeminiObject},
{NULL, NULL}
};
static const struct luaL_Reg geminiObjectLib_m [] = {
{"addEventListener", addEventListener},
{"__gc", geminiObjectGC},
{"__index", l_irc_index},
{"__newindex", l_irc_newindex},
{NULL, NULL}
};
int luaopen_geminiObjectLib (lua_State *L){
// create the metatable and put it into the registry
luaL_newmetatable(L, GEMINI_OBJECT_LUA_KEY);
lua_pushvalue(L, -1); // duplicates the metatable
luaL_setfuncs(L, geminiObjectLib_m, 0);
// create a table/library to hold the functions
luaL_newlib(L, geminiObjectLib_f);
NSLog(#"gemini lib opened");
return 1;
}
This code registers the library of functions (not show here) that provide the methods and metamethods for the GeminiObjects. The call to luaL_newmetatable creates a new metatable and associates it in the registry with the key GEMINI_OBJECT_LUA_KEY. GEMINI_OBJECT_LUA_KEY is just a unique string defined in the header. luaL_setfuncs actually adds the function pointers to the metatable, making them available as methods of the objects.

In case anyone is still interested, I got the answer to my question from the kind folks on the Lua mailing list. The problem here is that the library binding function luaopen_geminiObjectLib is not called before my call to addRuntimeObject.
Since iOS does not support dynamic libraries, I had added my libraries in statically by adding pointers to them to the preloadedlibs array in linit.c of the Lua source. Unfortunately, libraries added this way are not loaded until require('libname') is executed in a Lua script. Since I was calling my addRuntimeObject method prior to executing the Lua script, the library was not yet loaded.
The solution is to add the pointer to luaopen_geminiObjectLib to the loadedlibs array in the same linit.c file. This causes the library to be loaded when Lua starts up with no need for scripts to require it.

Related

Blockly How to create a Variable to the workspace (developer variable)

I want to create a Developer Variable to the workspace in Blockly, but I cannot find the necessary function/method.
I do not want to create the variable over a button. The variable should be included even if there is no block in the workspace.
With these two functions I can get the already created variables:
var variables = workspace.getAllVariables();
var dev_var = Blockly.Variables.allDeveloperVariables(workspace);
But what is the setting function?
Developer variables are variables that will never be visible to the user, but will exist in the generated code. If that's what you're looking for: there's no API for it, but here are some things you can do.
If you want to reserve the name so that users can't accidentally override your variable, call yourGenerator.addReservedWords('var1,var2,...'). You can initialize the variable in your wrapper code.
If you really want Blockly to both reserve and declare the variable for you, you could override the init function on your generator.
On the other hand, if what you want is a user-visible variable that always shows up in the toolbox, without the user creating it, you should call yourWorkspace.createVariable('variable_name').
The unit test blocks all assume that the variable unittestResults exists and can be written to. To indicate this, the block definition includes the function getDeveloperVars, which returns an array of strings. Each string is a variable name.Follow this issue in gtihub
Blockly.Blocks['unittest_fail'] = {
// Always assert an error.
init: function() {
this.setColour(65);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.appendDummyInput()
.appendField(new Blockly.FieldTextInput('test name'), 'MESSAGE')
.appendField('fail');
this.setTooltip('Records an error.');
},
getDeveloperVars: function() {
return ['unittestResults'];
}
};
LINK : https://github.com/google/blockly/issues/1535

QObject::findChildren() for QML object finding

I have an QML form with QQuickApplicationWindow. I need to get QQuickItem pointers on BaseKey elements of QtVirtualKeyboard (it's implementation is placed in separate QML file and loads with Loader of layout when program executes), but it has dynamical (runtime) type like this BaseKey_QMLTYPE_XX, where "XX" is a changeable number.
I found QObject::findChildren() function http://doc.qt.io/qt-4.8/qobject.html#findChild, but i cant find out number "XX" in typename.
How can i find QQuickItem pointer on BaseKey from C++ code?
BaseKey_QMLTYPE_XX looks like what you'd get if you printed the object (print(myObject)). I think that comes from QMetaObject::className().
If the object doesn't have an objectName set, you won't be able to find it using findChild() (unless you have access to the C++ type and there's only one object of that type).
I have a hacky test helper function that does something similar to what you're after:
QObject *TestHelper::findPopupFromTypeName(const QString &typeName) const
{
QObject *popup = nullptr;
foreach (QQuickItem *child, overlay->childItems()) {
if (QString::fromLatin1(child->metaObject()->className()) == "QQuickPopupItem") {
if (QString::fromLatin1(child->parent()->metaObject()->className()).contains(typeName)) {
popup = child->parent();
break;
}
}
}
return popup;
}
You could adapt this to iterate over the children of an object that you pass in. There are a couple more changes than that to get it to work, but the general idea is there.

qt5 proxy model updating too soon before main model update is done

I have a setup with a main model (QStandardModel), a proxy model which changes the output of the DisplayRole, and a separate tableview displaying each model. Inside the main model data is a user role that stores a pointer to another QObject which is used by the proxy model to get the desired display value.
I'm running into problems when the object pointed to by that variable is deleted. I am handling deletion in the main model via the destroyed(QObject*) signal. Inside the slot, I search through the model looking for any items that are pointing to the object and delete the reference.
That part works fine on its own but I also have connected to the onDataChanged(...) signal of the proxy model, where I call resizeColumnsToContents() on the proxy model. This then calls the proxy's data() function. Here I check to see if the item has a pointer and, if it does, get some information from the object for display.
The result of all this becomes:
Object about to be deleted triggers destroyed(...) signal
Main model looks for any items using the deleted object and calls setData to remove the reference
Tableview catches onDataChanged signal for the proxy model and resizes columns
Proxy model's data(...) is called. It checks if the item in the main model has the object pointer and, if so, displays a value from the object. If not, it displays something else.
The problem is, at step 4 the item from the main model apparently still hasn't been deleted; the pointer address is still stored. The object the pointer was referencing, though, has been deleted by this point resulting in a segfault.
How can I fix my setup to make sure the main model is finished deleting pointer references before the proxy model tries to update?
Also, here is pseudo-code for the relevant sections:
// elsewhere
Object *someObject = new QObject();
QModelIndex index = mainModel->index(0,0);
mainModel->setData(index, someObject, ObjectPtrRole);
// do stuff
delete someObject; // Qt is actually doing this, I'm not doing it explicitly
// MainModel
void MainModel::onObjectDestroyed(QObject *obj)
{
// iterating over all model items
// if item has pointer to obj
item->setData(QVariant::fromValue(NULL), ObjectPtrRole));
}
// receives onDataChanged signal
void onProxyModelDataChanged(...)
{
ui->tblProxyView->reseizeColumnsToContents();
}
void ProxyModel::data(const QModelIndex &index, int role) const
{
QModelIndex srcIndex = mapToSource(index);
if(role == Qt::DisplayRole)
{
QVariant v = sourceModel()->data(srcIndex, ObjectPtrRole);
Object *ptr = qvariant_cast<Object*>(v);
if(ptr != NULL)
return ptr->getDisplayData();
else
return sourceModel->data(srcIndex, role);
}
}
The problem is ptr is not NULL, but the referenced object is deleted, at the time ProxyModel::data(...) is called so I end up with a segfault.
To avoid dangling pointer dereferences with instances of QObject, you can do one of two things:
Use object->deleteLater - the object will be deleted once the control returns to the event loop. Such functionality is also known as autorelease pools.
Use a QPointer. It will set itself to null upon deletion of the object, so you can check it before use.

Get generic type using Mono embedded

How to I create a generic List<String> object using mono embedded calls? I can get List's MonoClass:
MonoClass* list = mono_class_from_name(mscorlibimage,
"System.Collections.Generic", "List`1");
and I see in docs that there's
mono_class_from_generic_parameter(MonoGenericParam*...)
but I have no idea where and how to get the MonoGenericParam. Or perhaps I need to construct a valid name for mono_class_from_name? I think this can be a bit slower but I'd accept that for now. I tried
MonoClass* list = mono_class_from_name(mscorlib::get().image, "System.Collections.Generic", "List`1[System.String]");
but no luck.
UPDATE:
OK I found a way. Still I'd like to see if there's an official way of doing thing, as this hack looks too dirty to me.
Basically I searched mono sources for generic methods and found mono_class_bind_generic_parameters (see https://raw.github.com/mono/mono/master/mono/metadata/reflection.c). I had to link to libmono-2.0.a in addition to .so to use it. But it worked:
extern "C" MonoClass*
mono_class_bind_generic_parameters(MonoClass *klass,
int type_argc, MonoType **types, bool is_dynamic);
MonoClass* list = mono_class_from_name(mscorlib::get().image,
"System.Collections.Generic", "List`1");
MonoClass* strcls = mono_class_from_name(mscorlib::get().image, "System", "String");
printf("str class: %p\n", strcls);
MonoType* strtype = mono_class_get_type(strcls);
printf("str type: %p\n", strtype);
MonoType* types[1];
types[0] = strtype;
list = mono_class_bind_generic_parameters(list, 1, types, false);
printf("list[string] class: %p\n", list);
MonoObject* obj = mono_object_new(domain, list);
printf("list[string] created: %p\n", obj);
I suppose I can take sources (UPDATE: hardly so) of these methods and reimplement them (they parse metadata, etc) - if I don't want to link to .a - but I wonder if there's a simpler way. Mono docs just don't answer anything, as they use to.
UPDATE: found this thread: http://mono.1490590.n4.nabble.com/Embedded-API-Method-signature-not-found-with-generic-parameter-td4660157.html which seems to say that no embedded API exists for what I want (i.e. they do not bother to expose mono_class_bind_generic_parameters). Can someone prove that it's correct? With that method, by the way, I get MonoReflectionType* and no way to get back MonoType* from it - while it is as easy to as getting ->type from the structure - which is internal and access via functions to it is internal. Mono Embedded should be called "Mono Internal" instead.
UPDATE: another method is to hack mono_class_inflate_generic_type using copy of internal structures:
struct _MonoGenericInst {
uint32_t id; /* unique ID for debugging */
uint32_t type_argc : 22; /* number of type arguments */
uint32_t is_open : 1; /* if this is an open type */
MonoType *type_argv [1];
};
struct _MonoGenericContext {
/* The instantiation corresponding to the class generic parameters */
MonoGenericInst *class_inst;
/* The instantiation corresponding to the method generic parameters */
void *method_inst;
};
_MonoGenericInst clsctx;
clsctx.type_argc = 1;
clsctx.is_open = 0;
clsctx.type_argv[0] = mono_class_get_type(System::String::_SClass());
MonoGenericContext ctx;
ctx.method_inst = 0;
ctx.class_inst = &clsctx;
MonoType* lt = mono_class_inflate_generic_type(
mono_class_get_type(System::Collections::Generic::List<System::String>::_SClass()),
&ctx);
This doesn't require static link to .a but is even a worse hack. And mono_class_inflate_generic_type is marked as DEPRECATED - so, if this is deprecated, then which is the modern one?
In many cases a mono embedding conundrum can be resolved by using a managed helper method. This is the approach used here.
So we have:
A managed helper method that accepts a generic type definition and an array of generic parameter types.
A client method that accepts a generic type definition name (e.g.: System.Collections.Generic.List`1), an assembly image that contains the type (or use an Assembly Qualified name) and an object of the required generic parameter type. We retrieve the underlying monoType for the object.
Note that when passing type info into the managed layer it has to be an instance of MonoReflectionType as obtained from mono_type_get_object().
The managed helper method is trivial and does the actual instantiation:
public static object CreateInstanceOfGenericType(Type genericTypeDefinition, Type[] parms)
{
// construct type from definition
Type constructedType = genericTypeDefinition.MakeGenericType(parms);
// create instance of constructed type
object obj = Activator.CreateInstance(constructedType);
return obj;
}
The helper code is called, in this case, from Objective-C:
+ (id)createInstanceOfGenericTypeDefinition:(char *)genericTypeDefinitionName monoImage:(MonoImage *)monoImage itemObject:(id)itemObject
{
// get the contained item monoType
MonoType *monoType = [DBType monoTypeForMonoObject:[itemObject monoObject]];
MonoReflectionType *monoReflectionType = mono_type_get_object([DBManagedEnvironment currentDomain], monoType);
// build a System.Array of item types
DBManagedObject *argType = [[DBManagedObject alloc] initWithMonoObject:(MonoObject *)monoReflectionType];
NSArray *argTypes = #[argType];
DBSystem_Array *dbsAargTypes = [argTypes dbsArrayWithTypeName:#"System.Type"];
// get the generic type definition
//
// Retrieves a MonoType from given name. If the name is not fully qualified,
// it defaults to get the type from the image or, if image is NULL or loading
// from it fails, uses corlib.
// This is the embedded equivalent of System.Type.GetType();
MonoType *monoGenericTypeDefinition = mono_reflection_type_from_name(genericTypeDefinitionName, monoImage);
// create instance using helper method
MonoMethod *helperMethod = [DBManagedEnvironment dubrovnikMonoMethodWithName:"CreateInstanceOfGenericType" className:"Dubrovnik.FrameworkHelper.GenericHelper" argCount:2];
void *hargs [2];
hargs[0] = mono_type_get_object([DBManagedEnvironment currentDomain], monoGenericTypeDefinition);
hargs[1] = [dbsAargTypes monoArray]; // a monoArray *
MonoObject *monoException = NULL;
MonoObject *monoObject = mono_runtime_invoke(helperMethod, NULL, hargs, &monoException);
if (monoException) NSRaiseExceptionFromMonoException(monoException);
id object = [System_Object subclassObjectWithMonoObject:monoObject];
return object;
}
For the complete code see Dubrovnik on Github

Creating Lua objects during callback issue

I making simple project on Delphi + Lua to use Delphi visual components through RTTI. Main implementation idea based on luna.h. I like Blizzard's idea of using templates stored in xml (when you can put several objects on TPanel for example and use it as template), so I almost implemented that also.
The problem is: everything works fine until I creating objects through callback from Lua made with almost same code as luna.h Inject code. If this object have "inherits" xml attribute callback function calls creation of objects stored in xml, creating another object through yet another injection. And I receive errors leading to lua51.dll.
Maybe that problem caused by using stack by both callback and Inject while callback function not returned result yet. So can I use stack and create objects through callback? If not - is there any workarounds to implement it? Blizzard really made it somehow.
More details:
1. Application registering Lua objects (for example TPanel and many others) through
cn := T.ClassName;
f := #StaticOnCreate;
lua_pushlightuserdata(L, self); // put offset to self into lightuserdata
lua_pushcclosure(L, f, 1);
lua_setglobal(L, PAnsiChar(UTF8Encode(cn))); // T() in lua will make a new instance.
difference from luna.h - application also stored pointer to object (Delphi objects are pointers) to avoid generics (c templates)
2. Now Lua have TPanel in global table
3. By using
p = TPanel("somename")
in script, Lua calls application's StaticOnCreate.
4. StaticOnCreate extracts object and calls class's function
o := TLuaClassTemplate(lua_topointer(L, lua_upvalueindex(1)));
result := o.OnCreate(L);
5. OnCreate function extracts params like name etc and creates exact visual object of type TPanel and by using same code as luna.h for inject function
lua_newtable(FL); // create a new table for the class object ('self')
obj_index := lua_gettop(FL);
lua_pushnumber(FL, 0);
a := lua_newuserdata(FL, SizeOf(pointer)); // store a ptr to the ptr
a^ := obj; // set the ptr to the ptr to point to the ptr... >.>
luaL_newmetatable(FL, PAnsiChar(UTF8Encode(cn))); // get (or create) the classname_metatable
lua_pushstring(FL, PAnsiChar(UTF8Encode('__gc')));
lua_pushlightuserdata(FL, self); // put offset to self into lightuserdata
lua_pushcclosure(FL, #StaticGc_T, 1);
lua_settable(FL, -3);
lua_setmetatable(FL, -2); // userdata.metatable = classname_metatable
lua_settable(FL, obj_index); // self[0] = obj;
f := #StaticThunk;
// register the functions
for i := 0 to length(ClassApiArray) - 1 do begin
lua_pushstring(FL, PAnsiChar(UTF8Encode(ClassApiArray[i].name)));
lua_pushlightuserdata(FL, self); // put offset to self into lightuserdata
lua_pushnumber(FL, i); // let the thunk know which method we mean
lua_pushcclosure(FL, f, 2);
lua_settable(FL, obj_index); // self["function"] = thunk("function")
end;
lua_pushvalue(FL, -1); // dup object on stack top
rec.ref := luaL_ref(FL, LUA_REGISTRYINDEX); // store object as ref
...
result := 1;
returns Lua object through stack, so now p from p = TPanel("somename") is object isntance.
But issue if I trying to implement xml templates and step 3
p = TPanel("somename", "xmltemplatenodename")
and during execution step 5 in OnCreate if I see there is inherits = xmltemplatenodename. So during step 5, before inject, application searching for exact xmltemplatenodename - if found creating more objects with inject for each object. And only after that continues execution of step 5 with own inject. Here I have errors leading to lua51.dll after creating 2-3 objects from xmltemplatenodename. But if application uses same xml as source and creates same xmltemplatenodename objects outside of OnCreate - there is no errors.
Inject for xml object slightly different, isntead of leaving object in stack it registers it by object name
lua_setglobal(FL, PAnsiChar(objName8));