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?
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.
The code in jdm's answer isn't compatible with Python 3. Since CObject
is deprecated in Python 2.7 and 3.1, and removed starting with 3.2, I tweaked the code to use Capsule
(available in 2.7 and since 3.1):
import ctypes, gi
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 PyGObjectCAPI(object):
def __init__(self):
self._as_void_ptr.restype = ctypes.c_void_p
self._as_void_ptr.argtypes = [ctypes.py_object]
addr = self._as_void_ptr(ctypes.py_object(
gi._gobject._PyGObject_API))
self._api = _PyGObject_Functions.from_address(addr)
@staticmethod
def _as_void_ptr(obj):
name = ctypes.pythonapi.PyCapsule_GetName(obj)
return ctypes.pythonapi.PyCapsule_GetPointer(obj, name)
def pygobject_new(self, addr):
return self._api.newgobj(addr)
capi = PyGObjectCAPI()
(I also renamed it to PyGobjectCAPI -- not sure if CPAI stood for something, but it made more sense to me this way.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With