Implementing sleep () within a GTK main loop

Recently I have been integrating some code which liberally used sleep() for its timing into a GTK main loop. I tried several different solutions and thought I’d mention a couple here.

The cutest one was to run the function with the sleep calls as a co-routine alongside a glib timer. "sleep (n)" gets replaced with "yield n".

import gobject
import gtk

def run_delayed_generator (generator):
    """Run this function with a generator as it's argument. Whenever
       that function performs a "yield n" then the function will be
       delayed by n seconds. i.e. "yield n" acts like "sleep (n)"
       without blocking the GTK main loop."""
    try:
        t = generator.next ()
        gobject.timeout_add (int (t*1000), run_delayed_generator,
                                           generator)
    except StopIteration:
        pass
    return False

def testsleeper ():
    print "a"
    yield 1
    print "b"
    yield 2
    print "c"
    yield 3
    print "d"
    gtk.main_quit ()

run_delayed_generator (testsleeper ())

gtk.main ()

Or, using a decorator:

def run_delayed (fn):
    def wrapper (*args):
        run_delayed_generator (fn (*args))
    return wrapper

@run_delayed
def testsleeper ():
  .
  .
  .

It’s got aesthetic appeal, but as the name “run_delayed” suggests, it isn’t really a sleep function. All hell breaks loose if a function using sleep calls another function using sleep. This approach does have its uses though: aisleriot uses a similar approach (written in a mix of scheme an C) to do the animations for auto-moves.

What I actually used was this:

def sleep (t):
    gobject.timeout_add (int (t*1000), gtk.main_quit)
    gtk.main ()

Far simpler, but you have to be very careful about calling gtk.main_quit () and there has to be a trailing gtk.main () to catch everything that falls off the end – but the code would normally have that anyway.


Posted

in

by

Tags: