Using gtk with threads? Write a decorator for gobject.idle_add

Hi there!

If you've ventured just a little bit into GTK and threading, you have probably noticed how things can explode if you manipulate GTK objects directly from a thread. GTK is not threadsafe.

However, this tip might help you get stuff done properly:

1) Do your actual work in a thread and give the thread callbacks for whenever it wants to update the UI. Keep those callbacks in your UT classes.
2) Make sure that those callbacks (since they are called from separate threads) add their work to the GTK work schedular with gobject.idle_add

Here is the decorator, you should use! Remember that since idle_add does not work with kwargs, your decorated method has to use positional arguments.

import gobject





def idle_add_decorator(func):  
    def callback(*args):  
        gobject.idle_add(func, *args)  
    return callback

Here is an example of using it:

class MyWindow(gtk.Window):





    def on_some_event(self, *args):





        @idle_add_decorator  
        def create_dialog():  
            dialog = gtk.MessageDialog(parent=None,  
                                       type=gtk.MESSAGE_QUESTION,  
                                       buttons = gtk.BUTTONS_YES_NO,  
                                       message_format="Are you sure?")  
            dialog.connect("response", hande_event)  
            dialog.connect("close", hande_event, gtk.RESPONSE_NO)  
            dialog.show()





        @idle_add_decorator  
        def hande_event(dialog, response_id, *args):  
            if dialog:  
                dialog.destroy()  
            if response_id == gtk.RESPONSE_NO:  
                return  
            try:





        def my_thread():  
            create_dialog()  
            while True:  
                print "Yo!"  
                time.sleep(10)





        t = threading.Thread(target=my_thread)  
        t.start()

So what's the example about? Well, we have my_thread - that's just a function that loops forever inside a thread. The first thing it does, however, is to create a gtk Dialog, and to do that, it should add itself to the job queue to avoid performing unsafe thread stuff. So that's where you add the decorator! And why does @idle_add_decorator also occur above hande_event? Well, it doesn't have to, because an event callback is already performed inside the GTK main loop - but basically, it will delay itself a little bit by moving down the queue at first, but on the other hand you might want to get some sort of habbit. Either always playing it safe by using the decorator - or - prefixing your event handlers with on_xxx so you know when something can only be called from the main thread.