[pygtk] gtk threads with a C extension module and callback

Kim Novak kim at trdlnk.com
Thu Feb 2 00:19:45 WST 2006


I am having an issue when I enable gtk threading (call 
gtk.threads_init() then gtk.main()). I'm not actually running any other 
threads yet but would like to, thus I have to call gtk.threads_init(). I 
don't know if this is a pygtk, gtk, python issue or user ignorance.

I've narrowed this down to a small example. The python code registers a 
callback with the C extension module then calls gtk.main. The C 
extension module registers a glib timeout event. When the timeout occurs 
the C code invokes the Python callback. It works if I don't call 
gtk.threads_init() and seg faults if I do.

The source is follows the commands I use to build and install the module 
and run the test:

   % python setup.py build
   % python setup.py install
   % python test.py

------ callbackmodule.c -------
#include <Python.h>
#include <glib.h>

static PyObject *my_callback = NULL;
static int counter = 0;

/* The timeout event handler for gtk event loop */
gint
on_timeout(gpointer data)
{
       PyObject *arglist;
       PyObject *result;

       /* Time to call the callback */
       arglist = Py_BuildValue("(i)", ++counter);
       result = PyEval_CallObject(my_callback, arglist);
       Py_DECREF(arglist);
       Py_DECREF(result);

       return 1;
}

static PyObject *
set_callback(PyObject *dummy, PyObject *args)
{
       PyObject *result = NULL;
       PyObject *temp;

       if (PyArg_ParseTuple(args, "O:set_callback", &temp)) {
               if (!PyCallable_Check(temp)) {
                       PyErr_SetString(PyExc_TypeError, "parameter must 
be callable");
                       return NULL;
               }
               Py_XINCREF(temp);         /* Add a reference to new 
callback */
               Py_XDECREF(my_callback);  /* Dispose of previous callback */
               my_callback = temp;       /* Remember new callback */

               /* register a timeout event for every 1 sec */
               g_timeout_add(1000, on_timeout, NULL);

               /* Boilerplate to return "None" */
               Py_INCREF(Py_None);
               result = Py_None;
       }
       return result;
}

static PyMethodDef CallbackMethods[] = {
       {"set_callback", set_callback, METH_VARARGS,
        "Register a callback."},

       {NULL, NULL, 0, NULL}        /* Sentinel */
};

PyMODINIT_FUNC
initcallback(void)
{
       (void)Py_InitModule("callback", CallbackMethods);
}

----- setup.py ------
from distutils.core import setup, Extension

module1 = Extension('callback',
                   include_dirs = 
['/usr/include/glib-2.0/','/usr/lib/glib-2.0/include'],
                   libraries = ['glib-2.0'],
                   library_dirs = ['/usr/lib'],
                   sources = ['callbackmodule.c'])

setup (name = 'PackageName',
      version = '1.0',
      description = 'This is a demo package',
      ext_modules = [module1])

---- test.py ----
import pygtk
pygtk.require("2.6")
import gtk
import callback

def test(arg):
 print "test called with", arg

callback.set_callback(test)

gtk.threads_init()
gtk.main()





More information about the pygtk mailing list