Search code examples
pythonctypespygobject

Create python object from memory address (using gi.repository)


Sometimes I need to call a gtk/gobject function that only exists in C, but returns an object that has a python wrapper. Previously I used a solution based on ctypes that worked well:

http://faq.pygtk.org/index.py?req=show&file=faq23.041.htp

Now that I swiched from PyGtk ("import gtk") to GObject-introspection ("from gi.repository import Gtk"), what can I use instead?


Solution

  • The _PyGObject_API interface has changed at some point. I needed to drop the register_sinkfunc function. The following works:

    from gi.repository import Gio, GLib
    import gi
    import ctypes
    
    class _PyGObject_Functions(ctypes.Structure):
       _fields_ = [
           ('register_class',
            ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p,
                              ctypes.c_int, ctypes.py_object,
                              ctypes.py_object)),
           ('register_wrapper',
            ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.py_object)),
           ('lookup_class',
            ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_int)),
           ('newgobj',
            ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
           ]
    
    class PyGObjectCPAI(object):
       def __init__(self):
           PyCObject_AsVoidPtr = ctypes.pythonapi.PyCObject_AsVoidPtr
           PyCObject_AsVoidPtr.restype = ctypes.c_void_p
           PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]
           addr = PyCObject_AsVoidPtr(ctypes.py_object(
               gi._gobject._PyGObject_API))
           self._api = _PyGObject_Functions.from_address(addr)
    
       def pygobject_new(self, addr):
           return self._api.newgobj(addr)
    
    capi = PyGObjectCPAI()
    

    To get an object from a pointer:

    obj = capi.pygobject_new(pointer)
    

    to get a pointer from a (g)object:

    pointer = hash(obj)
    

    I have to add, in my case this didn't help me solve my actual problem. I was trying to interface with dconf, but dconf returns values of type GVariant, which does not inherit from GObject. It seems PyGI/GObject unfortunately does not expose the neccessary functions to turn a C (*GVariant) into a Python GLib.Variant. I guess it's of those times when you have to throw away your initial approach and try something different.