pyGTK and Threading

I am in the process of adding a gnome gui interface to my soon-to-be released project. Incorporating Python, GTK, and Glade, I’ve run into several quirky issues relating to running threads and sharing access to GTK widgets. Often I will see a worker thread hanging until the window is closed, at which point it resumes operation, or a more serious error:

Gtk-ERROR **: file gtktextlayout.c: line 1990 (gtk_text_layout_get_line_display): should not be reached

which indicates an illegal cross-thread boundary violation.

After much searching, I found this site which fills in the story concerning pyGTK and threading very nicely.

First lets import the threading and gtk libraries we need:

import threading
try:
   import pygtk
   pygtk.require("2.0")
except:
try:
   import gtk
   import gtk.glade
except:
   sys.exit(1)

Next lets create a class which will be responsible for loading a window created in glade and operating on it

class MyWindow:
    def init(self):
        self.wTree = gtk.glade.XML('foofile.glade', 'mywindow')
        dic = { 'onbuttonclick' : self.buttonclick }
        self.wTree.signalauto_connect(dic)

def button_click(self, widget):
    # create worker thread
    threading.Thread(target=self.run).start()

# running in worker thread def run(self): self.wTree.getwidget(‘widgetname’).do_something()

The problem is the worker thread is trying to access the gtk widget created in the original thread, which throws the aforementioned exception. Luckily we can easily instruct python to pop into a gtk created thread, and then run the code, which does not result in the boundry violation. This is done easily by surrounding the widget access call with:

 gtk.gdk.threadsenter()
 self.wTree.getwidget('widgetname').dosomething()
 gtk.gdk.threads_leave()

Of course, for this to work, gtk will need to initialize its threading system, which you must explicitly do before you invoke gtk main:

if name == "main":
    hwg = MyWindow()
    gtk.gdk.threads_init()
    gtk.main()

Of course this is a simple example, but you so long as you initialize the gtk threading system, and pop into gtk threads before accessing / operating on widgets, you should have no problems with threading.