2011-12-29 11 views
6

A veces necesito llamar a una función gtk/gobject que solo existe en C, pero devuelve un objeto que tiene un contenedor python. Anteriormente he utilizado una solución basada en ctypes que funcionaba bien:Crear objeto python a partir de la dirección de memoria (usando gi.repository)

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

Ahora que swiched de PyGtk ("GTK importación") a GObject-introspección ("de importación gi.repository GTK"), lo que puede Yo uso en su lugar?

Respuesta

6

La interfaz _PyGObject_API ha cambiado en algún momento. Necesitaba soltar la función register_sinkfunc. Las siguientes obras:

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() 

para obtener un objeto desde un puntero:

obj = capi.pygobject_new(pointer) 

para obtener un puntero de una (g) objeto:

pointer = hash(obj) 

tengo que añadir, en mi caso esto no me ayudó a resolver mi problema real. Estaba tratando de interactuar con dconf, pero dconf devuelve valores de tipo GVariant, que no hereda de GObject. Parece que PyGI/GObject desafortunadamente no expone las funciones necesarias para convertir un C (* GVariant) en un Python GLib.Variant. Supongo que es en esos momentos cuando tienes que desechar tu enfoque inicial y probar algo diferente.

0

Con la llegada de archivos de inspección (.typelib, .gir), la misma API debería estar disponible independientemente del idioma utilizado, es decir, si está utilizando una función C que no está en la API, probablemente esté utilizando una función destinada a ser utilizada solo internamente.

+2

En teoría, eso es cierto. Sin embargo, quería utilizar una función de libdconf, y actualmente no hay ningún enlace para eso en mi sistema operativo (Ubuntu Oneric). Además, se puede pensar que uno tiene que ocuparse de una biblioteca personalizada (que no forma parte de Gtk & co.) Que devuelve un puntero a un GObject, por lo que en casos de nicho esto podría ser útil. – jdm

+0

@jdm Ya veo, gracias por sus comentarios. – jcollado

2

El código en jdm's answer no es compatible con Python 3. Desde CObject es deprecated en Python 2.7 y 3.1, y se retira a partir de 3,2, I Ajustado el código para utilizar Capsule (available en 2,7 y desde 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 también le cambió el nombre a PyGobjectC API -. no estoy seguro si CPAI representaba algo, pero tenía más sentido para mí de esta manera) api

1

PyGOject cambiado desde AlliedEnvy update

import gi 
import ctypes 
from ctypes import pythonapi 

class _PyGObject_Functions(ctypes.Structure): 
    _fields_ = [ 
     ('pygobject_register_class', 
      ctypes.PYFUNCTYPE(ctypes.c_void_p)), 
     ('pygobject_register_wrapper', 
      ctypes.PYFUNCTYPE(ctypes.c_void_p)), 
     ('pygobject_lookup_class', 
      ctypes.PYFUNCTYPE(ctypes.c_void_p)), 
     ('pygobject_new', 
      ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)), 
     ] 

    class PyGObjectCAPI(object): 
    def __init__(self): 
     addr = self._as_void_ptr(gi._gobject._PyGObject_API) 
     self._api = _PyGObject_Functions.from_address(addr) 

    @classmethod 
    def _capsule_name(cls, capsule): 
     pythonapi.PyCapsule_GetName.restype = ctypes.c_char_p 
     pythonapi.PyCapsule_GetName.argtypes = [ctypes.py_object] 
     return pythonapi.PyCapsule_GetName(capsule) 

    @classmethod 
    def _as_void_ptr(cls, capsule): 
     name = cls._capsule_name(capsule) 
     pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p 
     pythonapi.PyCapsule_GetPointer.argtypes = [ 
      ctypes.py_object, ctypes.c_char_p] 
     return pythonapi.PyCapsule_GetPointer(capsule, name) 

    def to_object(self, addr): 
     return self._api.pygobject_new(addr) 

capi = PyGObjectCAPI() 
Cuestiones relacionadas