Integrating a GTK+ C widget into Python
Last year I wrote a GTK+ widget to show and modify the properties of any
GObject. The widget was written in C for use in a C application. For another
project, I also have to modify the properties of GObjects but this time the
application is written in Python using PyGObject. Here’s how I did it.
Python extension
Obviously, a widget that is written in pure C and does not come with any
introspection data is unknown to Python’s type system. For this reason, we must
write a small extension module, that instantiates the object. In my case, I want
to call egg_property_tree_view_new() that either takes NULL or an object
that is going to be observed. First we include headers for Python, Python
GObject access and our widget:
#include <Python.h>
#include <pygobject.h>
#include "egg-property-tree-view.h"
Our module provides one function called create_property_view that takes a
GObject object and returns the constructed tree view object:
static PyObject *
First, let’s check if an argument was passed:
if
return NULL;
If the argument is not None, we unwrap the contained object with
pygobject_get():
observed = object == Py_None ? NULL : ;
if
goto err;
If everything is okay, we create a new widget with our C API, wrap it using
pygobject_new() and return it:
widget = ;
object = ;
return object;
If something unexpected happened, we throw a type error exception:
err:
;
return NULL;
}
Last but not least, we define our exported function and initialize our module.
Note, that you have to call init_pygobject() for GTK+ 2 or
pygobject_init() for GTK+ 3, or any attempt to call pygobject_foo() will
fail badly.
static PyMethodDef methods = ;
PyMODINIT_FUNC
Build environment
Once we have our Python wrapper together, we need to build it. For distribution
purposes it is a good idea to use distutils for that. Unfortunately, distutils
does not come with built-in support for pkg-config. Here I used a function
from the German Python forums that calls pkg-config and creates a dict1
for consumption by distutils.core.Extension. The following setup.py builds
the module using
=
= +
=
, = ,
=
, = ,
=
=
return
=
I had to change the code a bit, because GTK+ requires the -pthread cflag, on which the token “parser” chokes on.
Glueing everything together
Now,
python setup.py install
builds our extension module and installs it into the global site-packages or
– as I usually do – into a virtualenv. With everything in place, we can
happily mix and match objects created via GObject introspection or our own
wrappers:
=
=
There is a disadvantage of a hand-written wrapper compared to the generated
introspection data: you have to translate every C method manually. However, in
most cases, widgets are entirely characterized by their properties. Hence, a
Python programmer can use object.set_properties or object.props to change
the behaviour of the widget instead of calling
object.set_certain_property(value).