Search code examples
glibvalagobject

Is there a way to register types from gobject introspection?


I'm currently experimenting with the gobject-introspection library. One thing I would like to do is to be able to register types (classes in particular) from the information I can obtain. Specifically so I can get a GLib.Type which I can then use to instantiate a class with GLib.Object.new

I have successfully loaded a namespace from a typelib, and I can get information about the classes etc in the namespace, but I am uncertain how to move on from there?

static void main(string[] args){

    var rep = GI.Repository.get_default();
    rep.require("Gtk", null, 0);

    var oinfo = (GI.ObjectInfo)rep.find_by_name("Gtk", "Button");

}

from oinfo i can now easily obtain the name, etc. of the class, I have all the metadata there, as far as I can tell. But suppose I can not reference the type like: typeof(Gtk.Button) or otherwise directly refer to it in the code, how to I register this type with the type system so that I may instantiate it?


Solution

  • Right, so I have solved this myself, after a LOT of tinkering. But after all it turned out not to be so difficult. The most involved way to do this is using a shared library that has just been compiled, so my example will involve that:

    First, lets create a shared library containing just one class in one file:

    namespace TestLib{
    
        public class TestBase : Object{
    
            private static int counter = 0;
    
            public int count{
                get{
                    return ++counter;
                }
            }
    
        }
    
    }
    

    This needs to be compiled to a shared library file valac --library=TestLib -H TestLib-1.0.h --gir=TestLib-1.0.gir TestLib.vala -X -fPIC -X -shared -o TestLib.so Then use the gir compiler and generate the typelib g-ir-compiler --shared-library=TestLib TestLib-1.0.gir -o TestLib-1.0.typelib

    Then we write the program we want to run:

    using GI;
    
    namespace TestRunner{
    
        static int main(string[] args){
    
            var namesp = "TestLib"; //set the name of the namespace we want to load
            var rep = Repository.get_default(); //Obtain default repository
    
            rep.require_private(".", namesp, null, 0); //load namespace info from the current folder (this assumes the typelib is here)
    
            var rtinfo = (RegisteredTypeInfo)rep.find_by_name(namesp, "TestBase"); //retrieves the BaseInfo of any type in the "TestLib" namespace called "TestBase" and casts it
    
            var type = rtinfo.get_g_type(); //Calls the get type, registrering the type with the type system, so now it can be used as we wish
    
            var objt = Object.new(type); //object is instantiated, and we can use it
    
            Value val = Value(typeof(int));
            objt.get_property("count", ref val);
    
            message(val.get_int().to_string());
    
            objt.get_property("count", ref val);
    
            message(val.get_int().to_string());
    
            message("type is: %s".printf(type.name()));
    
            return 0;
    
        }
    
    }
    

    Then we compile this program: valac TestLib.vapi TestRunner.vala -X TestLib.so -X -I. -o testintro --pkg=gobject-introspection-1.0 And before we run it, we will remember to add this dir to the path, so the program knows where to find the shared library: export LD_LIBRARY_PATH=.

    finally we run the new program: ./testintro

    And we should see:

    ** Message: 22:45:18.556: TestRunner.vala:9: Chosen namespace is: TestLib
    ** Message: 22:45:18.556: TestRunner.vala:24: 1
    ** Message: 22:45:18.556: TestRunner.vala:28: 2
    ** Message: 22:45:18.556: TestRunner.vala:30: type is: TestLibTestBase