Hugo Hallqvist wrote:
Hello everyone,

I've recently had reason to investigate how to do asynchronous
notification from worker-threads to a main-thread (which handles all
gtk related function calls). After searching the web and mailing-lists
for pygtk for examples on this topic I found out about the following
possibilities:

1. Using gobject.io_add_watch() to watch a filehandle for activity.
There are several variations on this one:
1.1 Use a temporary file. (Doesn't work on windows.)
1.2 Use a AF_INET socket. (Does work on windows, but many "personal
firewalls" get suspicious about it, so an alternative solution is
probably preferred.)
1.3  Use os.pipe(). (This uses an extra thread per fd, due to glib's
gio_channel stuff, but otherwise should work fine.)
2. Lock the gdk-lock inside worker-thread and schedule an function to
be called within main-thread using gobject.idle_add() .
3. Use the gsource-module to make pygtk able to listen to a win32
event. It can be found here:
http://www.daa.com.au/pipermail/pygtk/2004-February/006961.html
I have briefly tested this technique, but didn't get it to work
reliably. This otherwise seems like a very good solution.

I've written a test-program which shows the points 2 and 1.3.  Both
work fine on my linux installation (debian unstable, python 2.3.5,
pygtk 2.4.1), however the example using pipes hangs when run in
windows (windows xp, python 2.3.4, pygtk 2.4.1).

Anyway, I've found a solution (point 2) which works reliably for me.
Maybe it would be good to document that it is not possible to use
os.pipe() with the gobject.io_add_watch() function on windows.

Any alternative solutions to the original problem apart from the ones
listed above would be greatly appreciated.

I think that gobject.idle_add is the simplest solution, and AFAIK you don't need to enter the gdk lock to call it. Note that you do need to enter the gdk lock inside the idle function if you are doing gui stuff in it.


If you're using Python 2.4, you can wrap it up as a decorator. The following code is untesed, and probably gratuitous :-)

    def idlefunction(function):
        def in_idle(args, kw):
            gtk.threads_enter()
            try:
                function(*args, **kw)
                return False
            finally:
                gtk.threads_leave()
        def wrapper(*args, **kw):
            gobject.idle_add(in_idle, args, kw)
        return wrapper

    @idlefunction
    def show_message(message):
        w = gtk.Window()
        w.add(gtk.Label(message))
        w.show_all()

--
Tim Evans
Applied Research Associates NZ
http://www.aranz.com/
_______________________________________________
pygtk mailing list   [email protected]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/

Reply via email to